diff --git a/samples/server-generator/scalatra/templates/build.sbt b/samples/server-generator/scalatra/templates/build.sbt index 0af07c030d5..ac1b8727dc9 100644 --- a/samples/server-generator/scalatra/templates/build.sbt +++ b/samples/server-generator/scalatra/templates/build.sbt @@ -16,7 +16,7 @@ libraryDependencies ++= Seq( "org.scalatra" % "scalatra-specs2" % "2.2.0-SNAPSHOT" % "test", "org.scalatra" % "scalatra-swagger" % "2.2.0-SNAPSHOT", "org.scalatra" % "scalatra-json" % "2.2.0-SNAPSHOT", - "org.json4s" %% "json4s-jackson" % "3.0.0-SNAPSHOT", + "org.json4s" %% "json4s-jackson" % "3.0.0", "com.wordnik" % "swagger-core_2.9.1" % "1.1.1-SNAPSHOT", "ch.qos.logback" % "logback-classic" % "1.0.6" % "runtime", "org.eclipse.jetty" % "jetty-webapp" % "8.1.5.v20120716" % "container", diff --git a/src/main/scala/com/wordnik/swagger/codegen/BasicJavaGenerator.scala b/src/main/scala/com/wordnik/swagger/codegen/BasicJavaGenerator.scala index 833d53debaf..52e6481efca 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/BasicJavaGenerator.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/BasicJavaGenerator.scala @@ -129,12 +129,7 @@ class BasicJavaGenerator extends BasicGenerator { case "List" => { val inner = { obj.items match { - case Some(items) => { - if(items.ref != null) - items.ref - else - items.`type` - } + case Some(items) => items.ref.getOrElse(items.`type`) case _ => throw new Exception("no inner type defined") } } @@ -159,12 +154,7 @@ class BasicJavaGenerator extends BasicGenerator { case "List" => { val inner = { obj.items match { - case Some(items) => { - if(items.ref != null) - items.ref - else - items.`type` - } + case Some(items) => items.ref.getOrElse(items.`type`) case _ => throw new Exception("no inner type defined") } } diff --git a/src/main/scala/com/wordnik/swagger/codegen/BasicPythonGenerator.scala b/src/main/scala/com/wordnik/swagger/codegen/BasicPythonGenerator.scala index 042d0ff1346..ade536761a9 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/BasicPythonGenerator.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/BasicPythonGenerator.scala @@ -139,12 +139,7 @@ class BasicPythonGenerator extends BasicGenerator { case "list" => { val inner = { obj.items match { - case Some(items) => { - if(items.ref != null) - items.ref - else - items.`type` - } + case Some(items) => items.ref.getOrElse(items.`type`) case _ => throw new Exception("no inner type defined") } } diff --git a/src/main/scala/com/wordnik/swagger/codegen/BasicScalaGenerator.scala b/src/main/scala/com/wordnik/swagger/codegen/BasicScalaGenerator.scala index 93bd9023f13..2951ed7899c 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/BasicScalaGenerator.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/BasicScalaGenerator.scala @@ -78,12 +78,7 @@ class BasicScalaGenerator extends BasicGenerator { case "Array" => { val inner = { obj.items match { - case Some(items) => { - if(items.ref != null) - items.ref - else - items.`type` - } + case Some(items) => items.ref.getOrElse(items.`type`) case _ => throw new Exception("no inner type defined") } } diff --git a/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala b/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala index 8c9e5f8e2af..def823d3867 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala @@ -364,12 +364,8 @@ class Codegen(config: CodegenConfig) { // import the container imports += Map("import" -> dt) propertyDocSchema.items match { - case Some(items) => { - if(items.ref != null) - baseType = items.ref - else if (items.`type` != null) - baseType = items.`type` - } + case Some(items) => + baseType = items.ref.getOrElse(items.`type`) case _ => } } diff --git a/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala b/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala index 89a9aced50a..d4dcf38890d 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala @@ -138,8 +138,8 @@ abstract class CodegenConfig { val inner = { obj.items match { case Some(items) => { - if(items.ref != null) - items.ref + if(items.ref != None) + items.ref.get else items.`type` } diff --git a/src/main/scala/com/wordnik/swagger/codegen/spec/SwaggerSpecValidator.scala b/src/main/scala/com/wordnik/swagger/codegen/spec/SwaggerSpecValidator.scala index 0bdb3cb1869..d21bb2208c0 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/spec/SwaggerSpecValidator.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/spec/SwaggerSpecValidator.scala @@ -182,13 +182,13 @@ class SwaggerSpecValidator(private val doc: ResourceListing, // process the sub object subObject.items match { case Some(item) => { - getUpdatedType(validModelNames, item.ref) match { + getUpdatedType(validModelNames, item.ref.get) match { case Some(updatedType) => { if (!item.ref.equals(updatedType)) { !!(model, MODEL_PROPERTY, format("%s->%s: %s", model.id, subObjectName, subObject.`type`), format("Invalid ref (%s). Best guess: %s", item.ref, updatedType)) LOGGER.finest("updated subObject.items.ref " + item.ref + " to " + updatedType) if (fix) { - subObject.items = Some(ModelRef(ref = updatedType)) + subObject.items = Some(ModelRef(null, Some(updatedType))) } } } @@ -202,12 +202,12 @@ class SwaggerSpecValidator(private val doc: ResourceListing, if (subObject.items != null && subObject.items != None && subObject.items.get.ref != null){ subObject.items match { case Some(item) => { - getUpdatedType(validModelNames, item.ref) match { + getUpdatedType(validModelNames, item.ref.get) match { case Some(updatedType) => { if (!item.ref.equals(updatedType)) { !!(model, MODEL_PROPERTY, format("%s->%s: %s", model.id, subObjectName, subObject.`type`), format("Invalid ref (%s). Best guess: %s", item.ref, updatedType)) LOGGER.finest("updated subObject.items.ref " + item.ref + " to " + updatedType) - if (fix) subObject.items = Some(ModelRef(ref = updatedType)) + if (fix) subObject.items = Some(ModelRef(null, Some(updatedType))) } } case None => { diff --git a/src/main/scala/com/wordnik/swagger/codegen/util/ApiExtractor.scala b/src/main/scala/com/wordnik/swagger/codegen/util/ApiExtractor.scala index facf2c601b2..352b89e0d01 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/util/ApiExtractor.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/util/ApiExtractor.scala @@ -18,6 +18,9 @@ package com.wordnik.swagger.codegen.util import com.wordnik.swagger.model._ +import org.json4s.jackson.JsonMethods._ +import org.json4s.native.Serialization.read + import java.net.URL import java.io.InputStream @@ -25,31 +28,31 @@ import scala.io._ import scala.collection.mutable.{ ListBuffer, HashMap, HashSet } object ApiExtractor extends RemoteUrl { - def json = ScalaJsonUtil.getJsonMapper + implicit val formats = SwaggerSerializers.formats def fetchApiListings(basePath: String, apis: List[ApiListingReference], apiKey: Option[String] = None): List[ApiListing] = { for (api <- apis) yield { - val str = basePath.startsWith("http") match { + val json = basePath.startsWith("http") match { case true => { println("calling: " + ((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json"))) urlToString((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json")) } case false => Source.fromFile((basePath + api.path).replaceAll(".\\{format\\}", ".json")).mkString } - json.readValue(str, classOf[ApiListing]) + parse(json).extract[ApiListing] } } def extractApiOperations(basePath: String, references: List[ApiListingReference], apiKey: Option[String] = None) = { for (api <- references) yield { - val str = basePath.startsWith("http") match { + val json = basePath.startsWith("http") match { case true => { println("calling: " + ((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json"))) urlToString((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json")) } case false => Source.fromFile((basePath + api.path).replaceAll(".\\{format\\}", ".json")).mkString } - json.readValue(str, classOf[ApiListing]) + parse(json).extract[ApiListing] } } diff --git a/src/main/scala/com/wordnik/swagger/codegen/util/CoreUtils.scala b/src/main/scala/com/wordnik/swagger/codegen/util/CoreUtils.scala index f0f57043bb7..de542c03a88 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/util/CoreUtils.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/util/CoreUtils.scala @@ -71,12 +71,7 @@ object CoreUtils { val subObject = prop._2 if (containers.contains(subObject.`type`)) { subObject.items match { - case Some(item) => { - if(item.ref != null) - subNames += item.ref - else - subNames += item.`type` - } + case Some(item) => subNames += item.ref.getOrElse(item.`type`) case None => } } @@ -129,11 +124,9 @@ object CoreUtils { if (containers.contains(subObject.`type`)) { subObject.items match { case Some(subItem) => { - if (subItem.ref != null) { - subNames += subItem.ref - } else { - subNames += subItem.`type` - } + val sn = subItem.ref.getOrElse(subItem.`type`) + if(sn != null) + subNames += sn } case _ => } @@ -148,11 +141,9 @@ object CoreUtils { if (containers.contains(subObject.`type`)) { subObject.items match { case Some(subItem) => { - if (subItem.ref != null) { - subNames += subItem.ref - } else { - subNames += subItem.`type` - } + val sn = subItem.ref.getOrElse(subItem.`type`) + if(sn != null) + subNames += sn } case _ => } diff --git a/src/main/scala/com/wordnik/swagger/codegen/util/ResourceExtractor.scala b/src/main/scala/com/wordnik/swagger/codegen/util/ResourceExtractor.scala index 73576f7d066..fbb98e27cf1 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/util/ResourceExtractor.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/util/ResourceExtractor.scala @@ -18,16 +18,19 @@ package com.wordnik.swagger.codegen.util import com.wordnik.swagger.model._ +import org.json4s.jackson.JsonMethods._ +import org.json4s.native.Serialization.read + import scala.io._ object ResourceExtractor extends RemoteUrl { - def json = ScalaJsonUtil.getJsonMapper + implicit val formats = SwaggerSerializers.formats def fetchListing(path: String, apiKey: Option[String] = None): ResourceListing = { - val str = path.startsWith("http") match { + val json = path.startsWith("http") match { case true => urlToString(path + apiKey.getOrElse("")) case false => Source.fromFile(path).mkString } - json.readValue(str, classOf[ResourceListing]) + parse(json).extract[ResourceListing] } } \ No newline at end of file diff --git a/src/main/scala/com/wordnik/swagger/model/AllowableValues.java b/src/main/scala/com/wordnik/swagger/model/AllowableValues.java deleted file mode 100644 index 9abd156127a..00000000000 --- a/src/main/scala/com/wordnik/swagger/model/AllowableValues.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2012 Wordnik, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.wordnik.swagger.model; - -import javax.xml.bind.annotation.*; - -import com.fasterxml.jackson.annotation.*; - -import static com.fasterxml.jackson.annotation.JsonTypeInfo.*; - -/** - * forgive me lord, for I used Java - * @SeeAlso https://issues.scala-lang.org/browse/SI-5165 - **/ -@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="valueType") -@JsonSubTypes({ - @JsonSubTypes.Type(value=AllowableListValues.class, name="LIST"), - @JsonSubTypes.Type(value=AllowableRangeValues.class, name="RANGE") -}) -public abstract class AllowableValues {} \ No newline at end of file diff --git a/src/main/scala/com/wordnik/swagger/model/SwaggerModelSerializer.scala b/src/main/scala/com/wordnik/swagger/model/SwaggerModelSerializer.scala index 580e8824f15..3a5dcc69ec4 100644 --- a/src/main/scala/com/wordnik/swagger/model/SwaggerModelSerializer.scala +++ b/src/main/scala/com/wordnik/swagger/model/SwaggerModelSerializer.scala @@ -5,8 +5,7 @@ import org.json4s.JsonDSL._ import org.json4s.jackson.JsonMethods._ import org.json4s.native.Serialization.{read, write} -import scala.collection.mutable.HashMap -import scala.collection.JavaConverters._ +import scala.collection.mutable.LinkedHashMap object SwaggerSerializers { implicit val formats = DefaultFormats + @@ -19,7 +18,40 @@ object SwaggerSerializers { new ErrorResponseSerializer + new ApiDescriptionSerializer + new ApiListingReferenceSerializer + - new ResourceListingSerializer + new ResourceListingSerializer + + new ApiListingSerializer + + class ApiListingSerializer extends CustomSerializer[ApiListing](formats => ({ + case json => + implicit val fmts: Formats = formats + ApiListing( + (json \ "apiVersion").extract[String], + (json \ "swaggerVersion").extract[String], + (json \ "basePath").extract[String], + (json \ "resourcePath").extract[String], + (json \ "apis").extract[List[ApiDescription]], + (json \ "models").extract[Map[String, Model]] + ) + }, { + case x: ApiListing => + implicit val fmts = formats + ("apiVersion" -> x.apiVersion) ~ + ("swaggerVersion" -> x.swaggerVersion) ~ + ("basePath" -> x.basePath) ~ + ("apis" -> { + x.apis match { + case e: List[ApiDescription] if (e.size > 0) => Extraction.decompose(e) + case _ => JNothing + } + }) ~ + ("models" -> { + x.models match { + case e: Map[String, Model] if (e.size > 0) => Extraction.decompose(e) + case _ => JNothing + } + }) + } + )) class ResourceListingSerializer extends CustomSerializer[ResourceListing](formats => ({ case json => @@ -103,7 +135,7 @@ object SwaggerSerializers { Operation( (json \ "httpMethod").extract[String], (json \ "summary").extract[String], - (json \ "notes").extract[String], + (json \ "notes").extractOrElse(""), (json \ "responseClass").extract[String], (json \ "nickname").extract[String], (json \ "parameters").extract[List[Parameter]], @@ -133,13 +165,13 @@ object SwaggerSerializers { case json => implicit val fmts: Formats = formats Parameter( - (json \ "name").extract[String], + (json \ "name").extractOrElse(""), (json \ "description").extract[String], - (json \ "defaultValue").extract[String], + (json \ "defaultValue").extractOrElse(""), (json \ "required").extractOrElse(false), (json \ "allowMultiple").extractOrElse(false), (json \ "dataType").extract[String], - (json \ "allowableValues").extract[AllowableValuesFoo], + (json \ "allowableValues").extract[AllowableValues], (json \ "paramType").extract[String] ) }, { @@ -154,7 +186,7 @@ object SwaggerSerializers { ("allowableValues" -> { x.allowableValues match { case Any => JNothing // don't serialize when not a concrete type - case e:AllowableValuesFoo => Extraction.decompose(x.allowableValues) + case e:AllowableValues => Extraction.decompose(x.allowableValues) case _ => JNothing } }) ~ @@ -165,7 +197,7 @@ object SwaggerSerializers { class ModelSerializer extends CustomSerializer[Model](formats => ({ case json => implicit val fmts: Formats = formats - val output = new HashMap[String, ModelProperty] + val output = new LinkedHashMap[String, ModelProperty] val properties = (json \ "properties") match { case JObject(entries) => { entries.map({ @@ -177,8 +209,8 @@ object SwaggerSerializers { Model( (json \ "id").extract[String], - (json \ "name").extract[String], - output.asJava, + (json \ "name").extractOrElse(""), + output, (json \ "description").extractOpt[String] ) }, { @@ -188,7 +220,7 @@ object SwaggerSerializers { ("name" -> x.name) ~ ("properties" -> { x.properties match { - case e:java.util.Map[String, ModelProperty] => Extraction.decompose(e.asScala.toMap) + case e: LinkedHashMap[String, ModelProperty] => Extraction.decompose(e.toMap) case _ => JNothing } }) @@ -202,7 +234,7 @@ object SwaggerSerializers { `type` = (json \ "type").extractOrElse(""), required = ((json \ "required").extractOrElse(false)), description = (json \ "description").extractOpt[String], - allowableValues = (json \ "allowableValues").extract[AllowableValuesFoo], + allowableValues = (json \ "allowableValues").extract[AllowableValues], items = (json \ "items").extractOpt[ModelRef] ) }, { @@ -214,7 +246,7 @@ object SwaggerSerializers { ("allowableValues" -> { x.allowableValues match { case Any => JNothing // don't serialize when not a concrete type - case e:AllowableValuesFoo => Extraction.decompose(x.allowableValues) + case e:AllowableValues => Extraction.decompose(x.allowableValues) case _ => JNothing } }) ~ @@ -226,18 +258,23 @@ object SwaggerSerializers { case json => implicit val fmts: Formats = formats ModelRef( - (json \ "$ref").extract[String], - (json \ "type").extract[String] + (json \ "type").extractOrElse(null: String), + (json \ "$ref").extractOpt[String] ) }, { case x: ModelRef => implicit val fmts = formats - ("$ref" -> x.ref) ~ - ("type" -> x.`type`) + ("type" -> { + x.`type` match { + case e:String => Some(e) + case _ => None + } + }) ~ + ("$ref" -> x.ref) } )) - class AllowableValuesSerializer extends CustomSerializer[AllowableValuesFoo](formats => ({ + class AllowableValuesSerializer extends CustomSerializer[AllowableValues](formats => ({ case json => implicit val fmts: Formats = formats json \ "valueType" match { diff --git a/src/main/scala/com/wordnik/swagger/model/SwaggerModels.scala b/src/main/scala/com/wordnik/swagger/model/SwaggerModels.scala index 1525d4140b0..02bbf76bb68 100644 --- a/src/main/scala/com/wordnik/swagger/model/SwaggerModels.scala +++ b/src/main/scala/com/wordnik/swagger/model/SwaggerModels.scala @@ -16,7 +16,7 @@ package com.wordnik.swagger.model -import com.fasterxml.jackson.annotation.{JsonProperty, JsonIgnore} +import scala.collection.mutable.LinkedHashMap case class ResourceListing( apiVersion: String, @@ -26,29 +26,27 @@ case class ResourceListing( case class ApiListingReference(path:String, description: String) -trait AllowableValuesFoo -case object Any extends AllowableValues with AllowableValuesFoo -case class AllowableListValues (values: List[String] = List(), valueType: String = "LIST") extends AllowableValues with AllowableValuesFoo -case class AllowableRangeValues(min: String, max: String) extends AllowableValues with AllowableValuesFoo +trait AllowableValues +case object Any extends AllowableValues +case class AllowableListValues (values: List[String] = List(), valueType: String = "LIST") extends AllowableValues +case class AllowableRangeValues(min: String, max: String) extends AllowableValues -// using java.util.Map because Jackon 2 isn't deserializing ListMap correctly, and ordered -// insertion is required case class Model( var id: String, var name: String, - var properties: java.util.Map[String, ModelProperty], + var properties: LinkedHashMap[String, ModelProperty], description: Option[String] = None) case class ModelProperty( var `type`: String, required: Boolean = false, description: Option[String] = None, - allowableValues: AllowableValuesFoo = Any, + allowableValues: AllowableValues = Any, var items: Option[ModelRef] = None) case class ModelRef( - @JsonProperty("$ref") ref: String = null, - `type`: String = null) + `type`: String, + ref: Option[String] = None) case class ApiListing ( apiVersion: String, @@ -80,7 +78,7 @@ case class Parameter ( required: Boolean, allowMultiple: Boolean, var dataType: String, - allowableValues: AllowableValuesFoo = Any, + allowableValues: AllowableValues = Any, paramType: String) case class ErrorResponse ( diff --git a/src/test/resources/petstore/pet.json b/src/test/resources/petstore/pet.json index fb71108cee8..7bea7c375e9 100644 --- a/src/test/resources/petstore/pet.json +++ b/src/test/resources/petstore/pet.json @@ -115,8 +115,7 @@ "available", "pending", "sold" - ], - "valueType":"LIST" + ] }, "required":true, "allowMultiple":true, @@ -197,8 +196,7 @@ "available", "pending", "sold" - ], - "valueType":"LIST" + ] }, "description":"pet status in the store", "type":"string" diff --git a/src/test/scala/BasicGeneratorTest.scala b/src/test/scala/BasicGeneratorTest.scala index 3c211f06a4a..4747dafb069 100644 --- a/src/test/scala/BasicGeneratorTest.scala +++ b/src/test/scala/BasicGeneratorTest.scala @@ -23,9 +23,7 @@ import org.scalatest.junit.JUnitRunner import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers -import scala.collection.JavaConverters._ -import scala.collection.mutable.HashMap -import scala.collection.immutable.ListMap +import scala.collection.mutable.{LinkedHashMap, HashMap} @RunWith(classOf[JUnitRunner]) class BasicGeneratorTest extends FlatSpec with ShouldMatchers { @@ -46,12 +44,14 @@ class BasicGeneratorTest extends FlatSpec with ShouldMatchers { it should "get operations" in { val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json") + val subDocs = ApiExtractor.fetchApiListings("src/test/resources/petstore", resourceListing.apis) - val allModels = new HashMap[String, Model]() + val allModels = new HashMap[String, Model] implicit val basePath = "http://localhost:8080/api" val generator = new SampleGenerator val ops = generator.extractApiOperations(subDocs, allModels) + allModels.size should be (5) ops.size should be (16) @@ -138,12 +138,12 @@ class BasicGeneratorTest extends FlatSpec with ShouldMatchers { Model( "SampleObject", "SampleObject", - Map( + LinkedHashMap( "stringValue" -> ModelProperty("string"), "intValue" -> ModelProperty("int"), "longValue" -> ModelProperty("long"), "floatValue" -> ModelProperty("float"), - "doubleValue" -> ModelProperty("double")).asJava, + "doubleValue" -> ModelProperty("double")), Some("a sample object")) } } diff --git a/src/test/scala/ModelSerializersTest.scala b/src/test/scala/ModelSerializersTest.scala index 99d92a4e06f..8682bafe49f 100644 --- a/src/test/scala/ModelSerializersTest.scala +++ b/src/test/scala/ModelSerializersTest.scala @@ -1,16 +1,16 @@ +import com.wordnik.swagger.model._ + import org.json4s._ import org.json4s.JsonDSL._ import org.json4s.jackson.JsonMethods._ import org.json4s.native.Serialization.{read, write} -import com.wordnik.swagger.model._ - import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers -import scala.collection.JavaConverters._ +import scala.collection.mutable.LinkedHashMap @RunWith(classOf[JUnitRunner]) class ResourceListingSerializersTest extends FlatSpec with ShouldMatchers { @@ -328,6 +328,12 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers { "type":"string", "required":false, "description":"name" + }, + "tags": { + "type":"Array", + "items": { + "type":"string" + } } }, "description":"nice model" @@ -339,9 +345,9 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers { model.id should be ("Foo") model.name should be ("Bar") model.properties should not be (null) - model.properties.size should be (2) + model.properties.size should be (3) model.description should be (Some("nice model")) - model.properties.asScala("id") match { + model.properties("id") match { case e: ModelProperty => { e.`type` should be ("string") e.required should be (true) @@ -349,7 +355,7 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers { } case _ => fail("missing property id") } - model.properties.asScala("name") match { + model.properties("name") match { case e: ModelProperty => { e.`type` should be ("string") e.required should be (false) @@ -357,13 +363,25 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers { } case _ => fail("missing property name") } + + model.properties("tags") match { + case e: ModelProperty => { + e.`type` should be ("Array") + e.required should be (false) + e.items match { + case Some(items) => items.`type` should be ("string") + case _ => fail("didn't find ref for Array") + } + } + case _ => fail("missing property name") + } } case _ => fail("expected type Model") } } it should "serialize a model" in { - val ref = Model("Foo", "Bar", (Map("s" -> ModelProperty("string", true, Some("a string")))).asJava) + val ref = Model("Foo", "Bar", (LinkedHashMap("s" -> ModelProperty("string", true, Some("a string"))))) write(ref) should be ("""{"id":"Foo","name":"Bar","properties":{"s":{"type":"string","required":true,"description":"a string"}}}""") } } @@ -382,7 +400,7 @@ class ModelRefSerializationTest extends FlatSpec with ShouldMatchers { val json = parse(jsonString) json.extract[ModelRef] match { case p: ModelRef => { - p.ref should be ("Foo") + p.ref should be (Some("Foo")) p.`type` should be ("Bar") } case _ => fail("expected type ModelRef") @@ -390,8 +408,8 @@ class ModelRefSerializationTest extends FlatSpec with ShouldMatchers { } it should "serialize a model ref" in { - val ref = ModelRef("Foo", "Bar") - write(ref) should be ("""{"$ref":"Foo","type":"Bar"}""") + val ref = ModelRef("Foo", Some("Bar")) + write(ref) should be ("""{"type":"Foo","$ref":"Bar"}""") } } @@ -410,8 +428,8 @@ class ModelPropertySerializationTest extends FlatSpec with ShouldMatchers { "values":["1","2","3"] }, "items":{ - "$ref":"Foo", - "type":"Bar" + "type":"Foo", + "$ref":"Bar" } } """ @@ -427,8 +445,8 @@ class ModelPropertySerializationTest extends FlatSpec with ShouldMatchers { } p.items match { case Some(e: ModelRef) => { - e.ref should be ("Foo") - e.`type` should be ("Bar") + e.`type` should be ("Foo") + e.ref should be (Some("Bar")) } case _ => fail("expected type ModelProperty") } @@ -438,8 +456,8 @@ class ModelPropertySerializationTest extends FlatSpec with ShouldMatchers { } it should "serialize a model property with allowable values and ref" in { - val p = ModelProperty("string", false, Some("nice"), AllowableListValues(List("a","b")),Some(ModelRef("Foo","Bar"))) - write(p) should be ("""{"type":"string","required":false,"description":"nice","allowableValues":{"valueType":"LIST","values":["a","b"]},"items":{"$ref":"Foo","type":"Bar"}}""") + val p = ModelProperty("string", false, Some("nice"), AllowableListValues(List("a","b")),Some(ModelRef("Foo",Some("Bar")))) + write(p) should be ("""{"type":"string","required":false,"description":"nice","allowableValues":{"valueType":"LIST","values":["a","b"]},"items":{"type":"Foo","$ref":"Bar"}}""") } it should "deserialize a model property with allowable values" in { @@ -511,7 +529,7 @@ class AllowableValuesSerializersTest extends FlatSpec with ShouldMatchers { } """ val json = parse(allowableValuesListString) - json.extract[AllowableValuesFoo] match { + json.extract[AllowableValues] match { case avl: AllowableListValues => { avl.valueType should be ("LIST") avl.values should be (List("1","2","3")) @@ -533,7 +551,7 @@ class AllowableValuesSerializersTest extends FlatSpec with ShouldMatchers { } """ val json = parse(allowableValuesRangeString) - json.extract[AllowableValuesFoo] match { + json.extract[AllowableValues] match { case avr: AllowableRangeValues => { avr.min should be ("abc") avr.max should be ("3") diff --git a/src/test/scala/SwaggerModelTest.scala b/src/test/scala/SwaggerModelTest.scala index ab814e58c4f..c6b07664146 100644 --- a/src/test/scala/SwaggerModelTest.scala +++ b/src/test/scala/SwaggerModelTest.scala @@ -15,7 +15,9 @@ */ import com.wordnik.swagger.model._ -import com.wordnik.swagger.codegen.util.ScalaJsonUtil + +import org.json4s.jackson.JsonMethods._ +import org.json4s.native.Serialization.read import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner @@ -24,141 +26,140 @@ import org.scalatest.matchers.ShouldMatchers import scala.io._ -import scala.collection.JavaConverters._ - @RunWith(classOf[JUnitRunner]) class SwaggerModelTest extends FlatSpec with ShouldMatchers { - val json = ScalaJsonUtil.getJsonMapper - behavior of "Swagger Model" + implicit val formats = SwaggerSerializers.formats - it should "deserialize ResourceListing" in { - val str = Source.fromFile("src/test/resources/petstore/resources.json").mkString - val listing = json.readValue(str, classOf[ResourceListing]) + behavior of "Swagger Model" - listing.apiVersion should be ("0.2") - listing.swaggerVersion should be ("1.1") - listing.basePath should be ("http://petstore.swagger.wordnik.com/api") - listing.apis.size should be (3) + it should "deserialize ResourceListing" in { + val json = Source.fromFile("src/test/resources/petstore/resources.json").mkString + val listing = parse(json).extract[ResourceListing] - val apis = listing.apis.map(api => (api.path, api.description)).toMap + listing.apiVersion should be ("0.2") + listing.swaggerVersion should be ("1.1") + listing.basePath should be ("http://petstore.swagger.wordnik.com/api") + listing.apis.size should be (3) - apis("/store.{format}") should be ("Operations about store") - apis("/pet.{format}") should be ("Operations about pets") - apis("/user.{format}") should be ("Operations about user") - } + val apis = listing.apis.map(api => (api.path, api.description)).toMap - it should "deserialize ApiListing" in { - val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString - val apiListing = json.readValue(str, classOf[ApiListing]) + apis("/store.{format}") should be ("Operations about store") + apis("/pet.{format}") should be ("Operations about pets") + apis("/user.{format}") should be ("Operations about user") + } - apiListing.apiVersion should be ("0.2") - apiListing.swaggerVersion should be ("1.1") - apiListing.basePath should be ("http://petstore.swagger.wordnik.com/api") - apiListing.resourcePath should be ("/pet") - apiListing.apis.size should be (4) - apiListing.models.size should be (3) + it should "deserialize ApiListing" in { + val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString + val apiListing = parse(json).extract[ApiListing] - val apiMap = apiListing.apis.map(api => (api.path, api)).toMap - val petBaseApi = apiMap("/pet.{format}/{petId}") - petBaseApi.description should be ("Operations about pets") - petBaseApi.operations.size should be (1) + apiListing.apiVersion should be ("0.2") + apiListing.swaggerVersion should be ("1.1") + apiListing.basePath should be ("http://petstore.swagger.wordnik.com/api") + apiListing.resourcePath should be ("/pet") + apiListing.apis.size should be (4) + apiListing.models.size should be (3) - val getPetById = petBaseApi.operations.head - getPetById.httpMethod should be ("GET") - getPetById.summary should be ("Find pet by ID") - getPetById.notes should be ("Returns a pet based on ID") - getPetById.responseClass should be ("Pet") + val apiMap = apiListing.apis.map(api => (api.path, api)).toMap + val petBaseApi = apiMap("/pet.{format}/{petId}") + petBaseApi.description should be ("Operations about pets") + petBaseApi.operations.size should be (1) - getPetById.nickname should be ("getPetById") - getPetById.parameters.size should be (1) + val getPetById = petBaseApi.operations.head + getPetById.httpMethod should be ("GET") + getPetById.summary should be ("Find pet by ID") + getPetById.notes should be ("Returns a pet based on ID") + getPetById.responseClass should be ("Pet") - val param = getPetById.parameters.head - param.name should be ("petId") - param.description should be ("ID of pet that needs to be fetched") - param.paramType should be ("path") - param.required should be (true) - param.allowMultiple should be (false) - param.dataType should be ("string") + getPetById.nickname should be ("getPetById") + getPetById.parameters.size should be (1) - getPetById.errorResponses.size should be (2) - val errors = getPetById.errorResponses.map(error => (error.code, error.reason)).toMap + val param = getPetById.parameters.head + param.name should be ("petId") + param.description should be ("ID of pet that needs to be fetched") + param.paramType should be ("path") + param.required should be (true) + param.allowMultiple should be (false) + param.dataType should be ("string") - errors(400) should be ("Invalid ID supplied") - errors(404) should be ("Pet not found") - } + getPetById.errorResponses.size should be (2) + val errors = getPetById.errorResponses.map(error => (error.code, error.reason)).toMap - it should "deserialize ApiListing with AllowableValues" in { - val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString - val apiListing = json.readValue(str, classOf[ApiListing]) - val apiMap = apiListing.apis.map(api => (api.path, api)).toMap - val petBaseApi = apiMap("/pet.{format}/findByStatus") - val findPetsByStatus = petBaseApi.operations.head - val param = findPetsByStatus.parameters.head + errors(400) should be ("Invalid ID supplied") + errors(404) should be ("Pet not found") + } - param.name should be ("status") - param.description should be ("Status values that need to be considered for filter") - param.paramType should be ("query") - param.required should be (true) - param.allowMultiple should be (true) - param.dataType should be ("string") - param.allowableValues should not be (null) + it should "deserialize ApiListing with AllowableValues" in { + val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString + val apiListing = parse(json).extract[ApiListing] + val apiMap = apiListing.apis.map(api => (api.path, api)).toMap + val petBaseApi = apiMap("/pet.{format}/findByStatus") + val findPetsByStatus = petBaseApi.operations.head + val param = findPetsByStatus.parameters.head - param.allowableValues.isInstanceOf[AllowableListValues] should be (true) - val allowableValues = param.allowableValues.asInstanceOf[AllowableListValues] - allowableValues.valueType should be ("LIST") - allowableValues.values.size should be (3) - (allowableValues.values.toSet & Set("available", "pending", "sold")).size should be (3) - } + param.name should be ("status") + param.description should be ("Status values that need to be considered for filter") + param.paramType should be ("query") + param.required should be (true) + param.allowMultiple should be (true) + param.dataType should be ("string") + param.allowableValues should not be (null) - it should "maintain model property order when deserializing" in { - val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString - val apiListing = json.readValue(str, classOf[ApiListing]) + param.allowableValues.isInstanceOf[AllowableListValues] should be (true) + val allowableValues = param.allowableValues.asInstanceOf[AllowableListValues] + allowableValues.valueType should be ("LIST") + allowableValues.values.size should be (3) + (allowableValues.values.toSet & Set("available", "pending", "sold")).size should be (3) + } - val models = apiListing.models - models.size should be (3) - val pet = models("Pet") + it should "maintain model property order when deserializing" in { + val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString + val apiListing = parse(json).extract[ApiListing] - val petProperties = pet.properties.asScala.toList + val models = apiListing.models + models.size should be (3) + val pet = models("Pet") - petProperties.size should be (6) - petProperties(0)._1 should be ("tags") - petProperties(1)._1 should be ("id") - petProperties(2)._1 should be ("category") - petProperties(3)._1 should be ("status") - petProperties(4)._1 should be ("name") - petProperties(5)._1 should be ("photoUrls") - } + val petProperties = pet.properties.toList - it should "deserialize models" in { - val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString - val apiListing = json.readValue(str, classOf[ApiListing]) + petProperties.size should be (6) + petProperties(0)._1 should be ("tags") + petProperties(1)._1 should be ("id") + petProperties(2)._1 should be ("category") + petProperties(3)._1 should be ("status") + petProperties(4)._1 should be ("name") + petProperties(5)._1 should be ("photoUrls") + } - val models = apiListing.models - models.size should be (3) + it should "deserialize models" in { + val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString + val apiListing = parse(json).extract[ApiListing] - val pet = models("Pet") - pet.id should be ("Pet") - pet.properties.size should be (6) + val models = apiListing.models + models.size should be (3) - val properties = pet.properties.asScala - val tags = properties("tags") - tags.`type` should be ("Array") - tags.items should not be (None) - tags.items.get.ref should be ("Tag") + val pet = models("Pet") + pet.id should be ("Pet") + pet.properties.size should be (6) - val id = properties("id") - // id.`type` shoud be ("long") + val properties = pet.properties + val tags = properties("tags") + tags.`type` should be ("Array") + tags.items should not be (None) + tags.items.get.ref should be (Some("Tag")) - val category = properties("category") - category.`type` should be ("Category") + val id = properties("id") + // id.`type` shoud be ("long") - val status = properties("status") - status.`type` should be ("string") - status.description should be (Some("pet status in the store")) - status.allowableValues should not be (null) - status.allowableValues.isInstanceOf[AllowableListValues] should be (true) - val allowableValues = status.allowableValues.asInstanceOf[AllowableListValues] - allowableValues.valueType should be ("LIST") - (allowableValues.values.toSet & Set("available", "pending", "sold")).size should be (3) - } + val category = properties("category") + category.`type` should be ("Category") + + val status = properties("status") + status.`type` should be ("string") + status.description should be (Some("pet status in the store")) + status.allowableValues should not be (null) + status.allowableValues.isInstanceOf[AllowableListValues] should be (true) + val allowableValues = status.allowableValues.asInstanceOf[AllowableListValues] + allowableValues.valueType should be ("LIST") + (allowableValues.values.toSet & Set("available", "pending", "sold")).size should be (3) + } } \ No newline at end of file diff --git a/src/test/scala/UtilsTest.scala b/src/test/scala/UtilsTest.scala index 6a5897b2593..969b72f6c5f 100644 --- a/src/test/scala/UtilsTest.scala +++ b/src/test/scala/UtilsTest.scala @@ -15,7 +15,7 @@ */ import com.wordnik.swagger.model._ -import com.wordnik.swagger.codegen.util._ +import com.wordnik.swagger.codegen.util.{ResourceExtractor, ApiExtractor, CoreUtils} import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner @@ -27,8 +27,6 @@ import scala.reflect.BeanProperty @RunWith(classOf[JUnitRunner]) class ResourceExtractorTest extends FlatSpec with ShouldMatchers { - val json = ScalaJsonUtil.getJsonMapper - behavior of "ResourceExtractor" it should "get 3 apis from a resource listing" in { val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json") @@ -39,12 +37,11 @@ class ResourceExtractorTest extends FlatSpec with ShouldMatchers { @RunWith(classOf[JUnitRunner]) class ApiExtractorTest extends FlatSpec with ShouldMatchers { - val json = ScalaJsonUtil.getJsonMapper - behavior of "ApiExtractor" it should "verify the deserialization of the store api" in { val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json") val docs = ApiExtractor.extractApiOperations("src/test/resources/petstore", resourceListing.apis) + val m = docs.map(t => (t.resourcePath, t)).toMap val storeApi = m("/store") @@ -68,7 +65,6 @@ class ApiExtractorTest extends FlatSpec with ShouldMatchers { @RunWith(classOf[JUnitRunner]) class CoreUtilsTest extends FlatSpec with ShouldMatchers { - val json = ScalaJsonUtil.getJsonMapper sys.props += "fileMap" -> "src/test/resources/petstore" behavior of "CoreUtils"