migrated to json4s

This commit is contained in:
Tony Tam 2012-12-04 00:15:55 -08:00
parent 25837e3367
commit 87bad7b36d
18 changed files with 257 additions and 270 deletions

View File

@ -16,7 +16,7 @@ libraryDependencies ++= Seq(
"org.scalatra" % "scalatra-specs2" % "2.2.0-SNAPSHOT" % "test", "org.scalatra" % "scalatra-specs2" % "2.2.0-SNAPSHOT" % "test",
"org.scalatra" % "scalatra-swagger" % "2.2.0-SNAPSHOT", "org.scalatra" % "scalatra-swagger" % "2.2.0-SNAPSHOT",
"org.scalatra" % "scalatra-json" % "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", "com.wordnik" % "swagger-core_2.9.1" % "1.1.1-SNAPSHOT",
"ch.qos.logback" % "logback-classic" % "1.0.6" % "runtime", "ch.qos.logback" % "logback-classic" % "1.0.6" % "runtime",
"org.eclipse.jetty" % "jetty-webapp" % "8.1.5.v20120716" % "container", "org.eclipse.jetty" % "jetty-webapp" % "8.1.5.v20120716" % "container",

View File

@ -129,12 +129,7 @@ class BasicJavaGenerator extends BasicGenerator {
case "List" => { case "List" => {
val inner = { val inner = {
obj.items match { obj.items match {
case Some(items) => { case Some(items) => items.ref.getOrElse(items.`type`)
if(items.ref != null)
items.ref
else
items.`type`
}
case _ => throw new Exception("no inner type defined") case _ => throw new Exception("no inner type defined")
} }
} }
@ -159,12 +154,7 @@ class BasicJavaGenerator extends BasicGenerator {
case "List" => { case "List" => {
val inner = { val inner = {
obj.items match { obj.items match {
case Some(items) => { case Some(items) => items.ref.getOrElse(items.`type`)
if(items.ref != null)
items.ref
else
items.`type`
}
case _ => throw new Exception("no inner type defined") case _ => throw new Exception("no inner type defined")
} }
} }

View File

@ -139,12 +139,7 @@ class BasicPythonGenerator extends BasicGenerator {
case "list" => { case "list" => {
val inner = { val inner = {
obj.items match { obj.items match {
case Some(items) => { case Some(items) => items.ref.getOrElse(items.`type`)
if(items.ref != null)
items.ref
else
items.`type`
}
case _ => throw new Exception("no inner type defined") case _ => throw new Exception("no inner type defined")
} }
} }

View File

@ -78,12 +78,7 @@ class BasicScalaGenerator extends BasicGenerator {
case "Array" => { case "Array" => {
val inner = { val inner = {
obj.items match { obj.items match {
case Some(items) => { case Some(items) => items.ref.getOrElse(items.`type`)
if(items.ref != null)
items.ref
else
items.`type`
}
case _ => throw new Exception("no inner type defined") case _ => throw new Exception("no inner type defined")
} }
} }

View File

@ -364,12 +364,8 @@ class Codegen(config: CodegenConfig) {
// import the container // import the container
imports += Map("import" -> dt) imports += Map("import" -> dt)
propertyDocSchema.items match { propertyDocSchema.items match {
case Some(items) => { case Some(items) =>
if(items.ref != null) baseType = items.ref.getOrElse(items.`type`)
baseType = items.ref
else if (items.`type` != null)
baseType = items.`type`
}
case _ => case _ =>
} }
} }

View File

@ -138,8 +138,8 @@ abstract class CodegenConfig {
val inner = { val inner = {
obj.items match { obj.items match {
case Some(items) => { case Some(items) => {
if(items.ref != null) if(items.ref != None)
items.ref items.ref.get
else else
items.`type` items.`type`
} }

View File

@ -182,13 +182,13 @@ class SwaggerSpecValidator(private val doc: ResourceListing,
// process the sub object // process the sub object
subObject.items match { subObject.items match {
case Some(item) => { case Some(item) => {
getUpdatedType(validModelNames, item.ref) match { getUpdatedType(validModelNames, item.ref.get) match {
case Some(updatedType) => { case Some(updatedType) => {
if (!item.ref.equals(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)) !!(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) LOGGER.finest("updated subObject.items.ref " + item.ref + " to " + updatedType)
if (fix) { 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){ if (subObject.items != null && subObject.items != None && subObject.items.get.ref != null){
subObject.items match { subObject.items match {
case Some(item) => { case Some(item) => {
getUpdatedType(validModelNames, item.ref) match { getUpdatedType(validModelNames, item.ref.get) match {
case Some(updatedType) => { case Some(updatedType) => {
if (!item.ref.equals(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)) !!(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) 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 => { case None => {

View File

@ -18,6 +18,9 @@ package com.wordnik.swagger.codegen.util
import com.wordnik.swagger.model._ import com.wordnik.swagger.model._
import org.json4s.jackson.JsonMethods._
import org.json4s.native.Serialization.read
import java.net.URL import java.net.URL
import java.io.InputStream import java.io.InputStream
@ -25,31 +28,31 @@ import scala.io._
import scala.collection.mutable.{ ListBuffer, HashMap, HashSet } import scala.collection.mutable.{ ListBuffer, HashMap, HashSet }
object ApiExtractor extends RemoteUrl { 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] = { def fetchApiListings(basePath: String, apis: List[ApiListingReference], apiKey: Option[String] = None): List[ApiListing] = {
for (api <- apis) yield { for (api <- apis) yield {
val str = basePath.startsWith("http") match { val json = basePath.startsWith("http") match {
case true => { case true => {
println("calling: " + ((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json"))) println("calling: " + ((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json")))
urlToString((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 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) = { def extractApiOperations(basePath: String, references: List[ApiListingReference], apiKey: Option[String] = None) = {
for (api <- references) yield { for (api <- references) yield {
val str = basePath.startsWith("http") match { val json = basePath.startsWith("http") match {
case true => { case true => {
println("calling: " + ((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json"))) println("calling: " + ((basePath + api.path + apiKey.getOrElse("")).replaceAll(".\\{format\\}", ".json")))
urlToString((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 case false => Source.fromFile((basePath + api.path).replaceAll(".\\{format\\}", ".json")).mkString
} }
json.readValue(str, classOf[ApiListing]) parse(json).extract[ApiListing]
} }
} }

View File

@ -71,12 +71,7 @@ object CoreUtils {
val subObject = prop._2 val subObject = prop._2
if (containers.contains(subObject.`type`)) { if (containers.contains(subObject.`type`)) {
subObject.items match { subObject.items match {
case Some(item) => { case Some(item) => subNames += item.ref.getOrElse(item.`type`)
if(item.ref != null)
subNames += item.ref
else
subNames += item.`type`
}
case None => case None =>
} }
} }
@ -129,11 +124,9 @@ object CoreUtils {
if (containers.contains(subObject.`type`)) { if (containers.contains(subObject.`type`)) {
subObject.items match { subObject.items match {
case Some(subItem) => { case Some(subItem) => {
if (subItem.ref != null) { val sn = subItem.ref.getOrElse(subItem.`type`)
subNames += subItem.ref if(sn != null)
} else { subNames += sn
subNames += subItem.`type`
}
} }
case _ => case _ =>
} }
@ -148,11 +141,9 @@ object CoreUtils {
if (containers.contains(subObject.`type`)) { if (containers.contains(subObject.`type`)) {
subObject.items match { subObject.items match {
case Some(subItem) => { case Some(subItem) => {
if (subItem.ref != null) { val sn = subItem.ref.getOrElse(subItem.`type`)
subNames += subItem.ref if(sn != null)
} else { subNames += sn
subNames += subItem.`type`
}
} }
case _ => case _ =>
} }

View File

@ -18,16 +18,19 @@ package com.wordnik.swagger.codegen.util
import com.wordnik.swagger.model._ import com.wordnik.swagger.model._
import org.json4s.jackson.JsonMethods._
import org.json4s.native.Serialization.read
import scala.io._ import scala.io._
object ResourceExtractor extends RemoteUrl { object ResourceExtractor extends RemoteUrl {
def json = ScalaJsonUtil.getJsonMapper implicit val formats = SwaggerSerializers.formats
def fetchListing(path: String, apiKey: Option[String] = None): ResourceListing = { 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 true => urlToString(path + apiKey.getOrElse(""))
case false => Source.fromFile(path).mkString case false => Source.fromFile(path).mkString
} }
json.readValue(str, classOf[ResourceListing]) parse(json).extract[ResourceListing]
} }
} }

View File

@ -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 {}

View File

@ -5,8 +5,7 @@ import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._ import org.json4s.jackson.JsonMethods._
import org.json4s.native.Serialization.{read, write} import org.json4s.native.Serialization.{read, write}
import scala.collection.mutable.HashMap import scala.collection.mutable.LinkedHashMap
import scala.collection.JavaConverters._
object SwaggerSerializers { object SwaggerSerializers {
implicit val formats = DefaultFormats + implicit val formats = DefaultFormats +
@ -19,7 +18,40 @@ object SwaggerSerializers {
new ErrorResponseSerializer + new ErrorResponseSerializer +
new ApiDescriptionSerializer + new ApiDescriptionSerializer +
new ApiListingReferenceSerializer + 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 => ({ class ResourceListingSerializer extends CustomSerializer[ResourceListing](formats => ({
case json => case json =>
@ -103,7 +135,7 @@ object SwaggerSerializers {
Operation( Operation(
(json \ "httpMethod").extract[String], (json \ "httpMethod").extract[String],
(json \ "summary").extract[String], (json \ "summary").extract[String],
(json \ "notes").extract[String], (json \ "notes").extractOrElse(""),
(json \ "responseClass").extract[String], (json \ "responseClass").extract[String],
(json \ "nickname").extract[String], (json \ "nickname").extract[String],
(json \ "parameters").extract[List[Parameter]], (json \ "parameters").extract[List[Parameter]],
@ -133,13 +165,13 @@ object SwaggerSerializers {
case json => case json =>
implicit val fmts: Formats = formats implicit val fmts: Formats = formats
Parameter( Parameter(
(json \ "name").extract[String], (json \ "name").extractOrElse(""),
(json \ "description").extract[String], (json \ "description").extract[String],
(json \ "defaultValue").extract[String], (json \ "defaultValue").extractOrElse(""),
(json \ "required").extractOrElse(false), (json \ "required").extractOrElse(false),
(json \ "allowMultiple").extractOrElse(false), (json \ "allowMultiple").extractOrElse(false),
(json \ "dataType").extract[String], (json \ "dataType").extract[String],
(json \ "allowableValues").extract[AllowableValuesFoo], (json \ "allowableValues").extract[AllowableValues],
(json \ "paramType").extract[String] (json \ "paramType").extract[String]
) )
}, { }, {
@ -154,7 +186,7 @@ object SwaggerSerializers {
("allowableValues" -> { ("allowableValues" -> {
x.allowableValues match { x.allowableValues match {
case Any => JNothing // don't serialize when not a concrete type 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 case _ => JNothing
} }
}) ~ }) ~
@ -165,7 +197,7 @@ object SwaggerSerializers {
class ModelSerializer extends CustomSerializer[Model](formats => ({ class ModelSerializer extends CustomSerializer[Model](formats => ({
case json => case json =>
implicit val fmts: Formats = formats implicit val fmts: Formats = formats
val output = new HashMap[String, ModelProperty] val output = new LinkedHashMap[String, ModelProperty]
val properties = (json \ "properties") match { val properties = (json \ "properties") match {
case JObject(entries) => { case JObject(entries) => {
entries.map({ entries.map({
@ -177,8 +209,8 @@ object SwaggerSerializers {
Model( Model(
(json \ "id").extract[String], (json \ "id").extract[String],
(json \ "name").extract[String], (json \ "name").extractOrElse(""),
output.asJava, output,
(json \ "description").extractOpt[String] (json \ "description").extractOpt[String]
) )
}, { }, {
@ -188,7 +220,7 @@ object SwaggerSerializers {
("name" -> x.name) ~ ("name" -> x.name) ~
("properties" -> { ("properties" -> {
x.properties match { 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 case _ => JNothing
} }
}) })
@ -202,7 +234,7 @@ object SwaggerSerializers {
`type` = (json \ "type").extractOrElse(""), `type` = (json \ "type").extractOrElse(""),
required = ((json \ "required").extractOrElse(false)), required = ((json \ "required").extractOrElse(false)),
description = (json \ "description").extractOpt[String], description = (json \ "description").extractOpt[String],
allowableValues = (json \ "allowableValues").extract[AllowableValuesFoo], allowableValues = (json \ "allowableValues").extract[AllowableValues],
items = (json \ "items").extractOpt[ModelRef] items = (json \ "items").extractOpt[ModelRef]
) )
}, { }, {
@ -214,7 +246,7 @@ object SwaggerSerializers {
("allowableValues" -> { ("allowableValues" -> {
x.allowableValues match { x.allowableValues match {
case Any => JNothing // don't serialize when not a concrete type 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 case _ => JNothing
} }
}) ~ }) ~
@ -226,18 +258,23 @@ object SwaggerSerializers {
case json => case json =>
implicit val fmts: Formats = formats implicit val fmts: Formats = formats
ModelRef( ModelRef(
(json \ "$ref").extract[String], (json \ "type").extractOrElse(null: String),
(json \ "type").extract[String] (json \ "$ref").extractOpt[String]
) )
}, { }, {
case x: ModelRef => case x: ModelRef =>
implicit val fmts = formats implicit val fmts = formats
("$ref" -> x.ref) ~ ("type" -> {
("type" -> x.`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 => case json =>
implicit val fmts: Formats = formats implicit val fmts: Formats = formats
json \ "valueType" match { json \ "valueType" match {

View File

@ -16,7 +16,7 @@
package com.wordnik.swagger.model package com.wordnik.swagger.model
import com.fasterxml.jackson.annotation.{JsonProperty, JsonIgnore} import scala.collection.mutable.LinkedHashMap
case class ResourceListing( case class ResourceListing(
apiVersion: String, apiVersion: String,
@ -26,29 +26,27 @@ case class ResourceListing(
case class ApiListingReference(path:String, description: String) case class ApiListingReference(path:String, description: String)
trait AllowableValuesFoo trait AllowableValues
case object Any extends AllowableValues with AllowableValuesFoo case object Any extends AllowableValues
case class AllowableListValues (values: List[String] = List(), valueType: String = "LIST") extends AllowableValues with AllowableValuesFoo case class AllowableListValues (values: List[String] = List(), valueType: String = "LIST") extends AllowableValues
case class AllowableRangeValues(min: String, max: String) extends AllowableValues with AllowableValuesFoo 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( case class Model(
var id: String, var id: String,
var name: String, var name: String,
var properties: java.util.Map[String, ModelProperty], var properties: LinkedHashMap[String, ModelProperty],
description: Option[String] = None) description: Option[String] = None)
case class ModelProperty( case class ModelProperty(
var `type`: String, var `type`: String,
required: Boolean = false, required: Boolean = false,
description: Option[String] = None, description: Option[String] = None,
allowableValues: AllowableValuesFoo = Any, allowableValues: AllowableValues = Any,
var items: Option[ModelRef] = None) var items: Option[ModelRef] = None)
case class ModelRef( case class ModelRef(
@JsonProperty("$ref") ref: String = null, `type`: String,
`type`: String = null) ref: Option[String] = None)
case class ApiListing ( case class ApiListing (
apiVersion: String, apiVersion: String,
@ -80,7 +78,7 @@ case class Parameter (
required: Boolean, required: Boolean,
allowMultiple: Boolean, allowMultiple: Boolean,
var dataType: String, var dataType: String,
allowableValues: AllowableValuesFoo = Any, allowableValues: AllowableValues = Any,
paramType: String) paramType: String)
case class ErrorResponse ( case class ErrorResponse (

View File

@ -115,8 +115,7 @@
"available", "available",
"pending", "pending",
"sold" "sold"
], ]
"valueType":"LIST"
}, },
"required":true, "required":true,
"allowMultiple":true, "allowMultiple":true,
@ -197,8 +196,7 @@
"available", "available",
"pending", "pending",
"sold" "sold"
], ]
"valueType":"LIST"
}, },
"description":"pet status in the store", "description":"pet status in the store",
"type":"string" "type":"string"

View File

@ -23,9 +23,7 @@ import org.scalatest.junit.JUnitRunner
import org.scalatest.FlatSpec import org.scalatest.FlatSpec
import org.scalatest.matchers.ShouldMatchers import org.scalatest.matchers.ShouldMatchers
import scala.collection.JavaConverters._ import scala.collection.mutable.{LinkedHashMap, HashMap}
import scala.collection.mutable.HashMap
import scala.collection.immutable.ListMap
@RunWith(classOf[JUnitRunner]) @RunWith(classOf[JUnitRunner])
class BasicGeneratorTest extends FlatSpec with ShouldMatchers { class BasicGeneratorTest extends FlatSpec with ShouldMatchers {
@ -46,12 +44,14 @@ class BasicGeneratorTest extends FlatSpec with ShouldMatchers {
it should "get operations" in { it should "get operations" in {
val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json") val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json")
val subDocs = ApiExtractor.fetchApiListings("src/test/resources/petstore", resourceListing.apis) 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" implicit val basePath = "http://localhost:8080/api"
val generator = new SampleGenerator val generator = new SampleGenerator
val ops = generator.extractApiOperations(subDocs, allModels) val ops = generator.extractApiOperations(subDocs, allModels)
allModels.size should be (5) allModels.size should be (5)
ops.size should be (16) ops.size should be (16)
@ -138,12 +138,12 @@ class BasicGeneratorTest extends FlatSpec with ShouldMatchers {
Model( Model(
"SampleObject", "SampleObject",
"SampleObject", "SampleObject",
Map( LinkedHashMap(
"stringValue" -> ModelProperty("string"), "stringValue" -> ModelProperty("string"),
"intValue" -> ModelProperty("int"), "intValue" -> ModelProperty("int"),
"longValue" -> ModelProperty("long"), "longValue" -> ModelProperty("long"),
"floatValue" -> ModelProperty("float"), "floatValue" -> ModelProperty("float"),
"doubleValue" -> ModelProperty("double")).asJava, "doubleValue" -> ModelProperty("double")),
Some("a sample object")) Some("a sample object"))
} }
} }

View File

@ -1,16 +1,16 @@
import com.wordnik.swagger.model._
import org.json4s._ import org.json4s._
import org.json4s.JsonDSL._ import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._ import org.json4s.jackson.JsonMethods._
import org.json4s.native.Serialization.{read, write} import org.json4s.native.Serialization.{read, write}
import com.wordnik.swagger.model._
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner import org.scalatest.junit.JUnitRunner
import org.scalatest.FlatSpec import org.scalatest.FlatSpec
import org.scalatest.matchers.ShouldMatchers import org.scalatest.matchers.ShouldMatchers
import scala.collection.JavaConverters._ import scala.collection.mutable.LinkedHashMap
@RunWith(classOf[JUnitRunner]) @RunWith(classOf[JUnitRunner])
class ResourceListingSerializersTest extends FlatSpec with ShouldMatchers { class ResourceListingSerializersTest extends FlatSpec with ShouldMatchers {
@ -328,6 +328,12 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers {
"type":"string", "type":"string",
"required":false, "required":false,
"description":"name" "description":"name"
},
"tags": {
"type":"Array",
"items": {
"type":"string"
}
} }
}, },
"description":"nice model" "description":"nice model"
@ -339,9 +345,9 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers {
model.id should be ("Foo") model.id should be ("Foo")
model.name should be ("Bar") model.name should be ("Bar")
model.properties should not be (null) 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.description should be (Some("nice model"))
model.properties.asScala("id") match { model.properties("id") match {
case e: ModelProperty => { case e: ModelProperty => {
e.`type` should be ("string") e.`type` should be ("string")
e.required should be (true) e.required should be (true)
@ -349,7 +355,7 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers {
} }
case _ => fail("missing property id") case _ => fail("missing property id")
} }
model.properties.asScala("name") match { model.properties("name") match {
case e: ModelProperty => { case e: ModelProperty => {
e.`type` should be ("string") e.`type` should be ("string")
e.required should be (false) e.required should be (false)
@ -357,13 +363,25 @@ class ModelSerializationTest extends FlatSpec with ShouldMatchers {
} }
case _ => fail("missing property name") 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") case _ => fail("expected type Model")
} }
} }
it should "serialize a model" in { 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"}}}""") 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) val json = parse(jsonString)
json.extract[ModelRef] match { json.extract[ModelRef] match {
case p: ModelRef => { case p: ModelRef => {
p.ref should be ("Foo") p.ref should be (Some("Foo"))
p.`type` should be ("Bar") p.`type` should be ("Bar")
} }
case _ => fail("expected type ModelRef") case _ => fail("expected type ModelRef")
@ -390,8 +408,8 @@ class ModelRefSerializationTest extends FlatSpec with ShouldMatchers {
} }
it should "serialize a model ref" in { it should "serialize a model ref" in {
val ref = ModelRef("Foo", "Bar") val ref = ModelRef("Foo", Some("Bar"))
write(ref) should be ("""{"$ref":"Foo","type":"Bar"}""") write(ref) should be ("""{"type":"Foo","$ref":"Bar"}""")
} }
} }
@ -410,8 +428,8 @@ class ModelPropertySerializationTest extends FlatSpec with ShouldMatchers {
"values":["1","2","3"] "values":["1","2","3"]
}, },
"items":{ "items":{
"$ref":"Foo", "type":"Foo",
"type":"Bar" "$ref":"Bar"
} }
} }
""" """
@ -427,8 +445,8 @@ class ModelPropertySerializationTest extends FlatSpec with ShouldMatchers {
} }
p.items match { p.items match {
case Some(e: ModelRef) => { case Some(e: ModelRef) => {
e.ref should be ("Foo") e.`type` should be ("Foo")
e.`type` should be ("Bar") e.ref should be (Some("Bar"))
} }
case _ => fail("expected type ModelProperty") 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 { 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"))) 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":{"$ref":"Foo","type":"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 { it should "deserialize a model property with allowable values" in {
@ -511,7 +529,7 @@ class AllowableValuesSerializersTest extends FlatSpec with ShouldMatchers {
} }
""" """
val json = parse(allowableValuesListString) val json = parse(allowableValuesListString)
json.extract[AllowableValuesFoo] match { json.extract[AllowableValues] match {
case avl: AllowableListValues => { case avl: AllowableListValues => {
avl.valueType should be ("LIST") avl.valueType should be ("LIST")
avl.values should be (List("1","2","3")) avl.values should be (List("1","2","3"))
@ -533,7 +551,7 @@ class AllowableValuesSerializersTest extends FlatSpec with ShouldMatchers {
} }
""" """
val json = parse(allowableValuesRangeString) val json = parse(allowableValuesRangeString)
json.extract[AllowableValuesFoo] match { json.extract[AllowableValues] match {
case avr: AllowableRangeValues => { case avr: AllowableRangeValues => {
avr.min should be ("abc") avr.min should be ("abc")
avr.max should be ("3") avr.max should be ("3")

View File

@ -15,7 +15,9 @@
*/ */
import com.wordnik.swagger.model._ 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.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner import org.scalatest.junit.JUnitRunner
@ -24,141 +26,140 @@ import org.scalatest.matchers.ShouldMatchers
import scala.io._ import scala.io._
import scala.collection.JavaConverters._
@RunWith(classOf[JUnitRunner]) @RunWith(classOf[JUnitRunner])
class SwaggerModelTest extends FlatSpec with ShouldMatchers { class SwaggerModelTest extends FlatSpec with ShouldMatchers {
val json = ScalaJsonUtil.getJsonMapper implicit val formats = SwaggerSerializers.formats
behavior of "Swagger Model"
it should "deserialize ResourceListing" in { behavior of "Swagger Model"
val str = Source.fromFile("src/test/resources/petstore/resources.json").mkString
val listing = json.readValue(str, classOf[ResourceListing])
listing.apiVersion should be ("0.2") it should "deserialize ResourceListing" in {
listing.swaggerVersion should be ("1.1") val json = Source.fromFile("src/test/resources/petstore/resources.json").mkString
listing.basePath should be ("http://petstore.swagger.wordnik.com/api") val listing = parse(json).extract[ResourceListing]
listing.apis.size should be (3)
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") val apis = listing.apis.map(api => (api.path, api.description)).toMap
apis("/pet.{format}") should be ("Operations about pets")
apis("/user.{format}") should be ("Operations about user")
}
it should "deserialize ApiListing" in { apis("/store.{format}") should be ("Operations about store")
val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString apis("/pet.{format}") should be ("Operations about pets")
val apiListing = json.readValue(str, classOf[ApiListing]) apis("/user.{format}") should be ("Operations about user")
}
apiListing.apiVersion should be ("0.2") it should "deserialize ApiListing" in {
apiListing.swaggerVersion should be ("1.1") val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString
apiListing.basePath should be ("http://petstore.swagger.wordnik.com/api") val apiListing = parse(json).extract[ApiListing]
apiListing.resourcePath should be ("/pet")
apiListing.apis.size should be (4)
apiListing.models.size should be (3)
val apiMap = apiListing.apis.map(api => (api.path, api)).toMap apiListing.apiVersion should be ("0.2")
val petBaseApi = apiMap("/pet.{format}/{petId}") apiListing.swaggerVersion should be ("1.1")
petBaseApi.description should be ("Operations about pets") apiListing.basePath should be ("http://petstore.swagger.wordnik.com/api")
petBaseApi.operations.size should be (1) apiListing.resourcePath should be ("/pet")
apiListing.apis.size should be (4)
apiListing.models.size should be (3)
val getPetById = petBaseApi.operations.head val apiMap = apiListing.apis.map(api => (api.path, api)).toMap
getPetById.httpMethod should be ("GET") val petBaseApi = apiMap("/pet.{format}/{petId}")
getPetById.summary should be ("Find pet by ID") petBaseApi.description should be ("Operations about pets")
getPetById.notes should be ("Returns a pet based on ID") petBaseApi.operations.size should be (1)
getPetById.responseClass should be ("Pet")
getPetById.nickname should be ("getPetById") val getPetById = petBaseApi.operations.head
getPetById.parameters.size should be (1) 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 getPetById.nickname should be ("getPetById")
param.name should be ("petId") getPetById.parameters.size should be (1)
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.errorResponses.size should be (2) val param = getPetById.parameters.head
val errors = getPetById.errorResponses.map(error => (error.code, error.reason)).toMap 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") getPetById.errorResponses.size should be (2)
errors(404) should be ("Pet not found") val errors = getPetById.errorResponses.map(error => (error.code, error.reason)).toMap
}
it should "deserialize ApiListing with AllowableValues" in { errors(400) should be ("Invalid ID supplied")
val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString errors(404) should be ("Pet not found")
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
param.name should be ("status") it should "deserialize ApiListing with AllowableValues" in {
param.description should be ("Status values that need to be considered for filter") val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString
param.paramType should be ("query") val apiListing = parse(json).extract[ApiListing]
param.required should be (true) val apiMap = apiListing.apis.map(api => (api.path, api)).toMap
param.allowMultiple should be (true) val petBaseApi = apiMap("/pet.{format}/findByStatus")
param.dataType should be ("string") val findPetsByStatus = petBaseApi.operations.head
param.allowableValues should not be (null) val param = findPetsByStatus.parameters.head
param.allowableValues.isInstanceOf[AllowableListValues] should be (true) param.name should be ("status")
val allowableValues = param.allowableValues.asInstanceOf[AllowableListValues] param.description should be ("Status values that need to be considered for filter")
allowableValues.valueType should be ("LIST") param.paramType should be ("query")
allowableValues.values.size should be (3) param.required should be (true)
(allowableValues.values.toSet & Set("available", "pending", "sold")).size should be (3) 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 { param.allowableValues.isInstanceOf[AllowableListValues] should be (true)
val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString val allowableValues = param.allowableValues.asInstanceOf[AllowableListValues]
val apiListing = json.readValue(str, classOf[ApiListing]) 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 it should "maintain model property order when deserializing" in {
models.size should be (3) val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString
val pet = models("Pet") 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) val petProperties = pet.properties.toList
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")
}
it should "deserialize models" in { petProperties.size should be (6)
val str = Source.fromFile("src/test/resources/petstore/pet.json").mkString petProperties(0)._1 should be ("tags")
val apiListing = json.readValue(str, classOf[ApiListing]) 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 it should "deserialize models" in {
models.size should be (3) val json = Source.fromFile("src/test/resources/petstore/pet.json").mkString
val apiListing = parse(json).extract[ApiListing]
val pet = models("Pet") val models = apiListing.models
pet.id should be ("Pet") models.size should be (3)
pet.properties.size should be (6)
val properties = pet.properties.asScala val pet = models("Pet")
val tags = properties("tags") pet.id should be ("Pet")
tags.`type` should be ("Array") pet.properties.size should be (6)
tags.items should not be (None)
tags.items.get.ref should be ("Tag")
val id = properties("id") val properties = pet.properties
// id.`type` shoud be ("long") 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") val id = properties("id")
category.`type` should be ("Category") // id.`type` shoud be ("long")
val status = properties("status") val category = properties("category")
status.`type` should be ("string") category.`type` should be ("Category")
status.description should be (Some("pet status in the store"))
status.allowableValues should not be (null) val status = properties("status")
status.allowableValues.isInstanceOf[AllowableListValues] should be (true) status.`type` should be ("string")
val allowableValues = status.allowableValues.asInstanceOf[AllowableListValues] status.description should be (Some("pet status in the store"))
allowableValues.valueType should be ("LIST") status.allowableValues should not be (null)
(allowableValues.values.toSet & Set("available", "pending", "sold")).size should be (3) 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)
}
} }

View File

@ -15,7 +15,7 @@
*/ */
import com.wordnik.swagger.model._ 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.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner import org.scalatest.junit.JUnitRunner
@ -27,8 +27,6 @@ import scala.reflect.BeanProperty
@RunWith(classOf[JUnitRunner]) @RunWith(classOf[JUnitRunner])
class ResourceExtractorTest extends FlatSpec with ShouldMatchers { class ResourceExtractorTest extends FlatSpec with ShouldMatchers {
val json = ScalaJsonUtil.getJsonMapper
behavior of "ResourceExtractor" behavior of "ResourceExtractor"
it should "get 3 apis from a resource listing" in { it should "get 3 apis from a resource listing" in {
val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json") val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json")
@ -39,12 +37,11 @@ class ResourceExtractorTest extends FlatSpec with ShouldMatchers {
@RunWith(classOf[JUnitRunner]) @RunWith(classOf[JUnitRunner])
class ApiExtractorTest extends FlatSpec with ShouldMatchers { class ApiExtractorTest extends FlatSpec with ShouldMatchers {
val json = ScalaJsonUtil.getJsonMapper
behavior of "ApiExtractor" behavior of "ApiExtractor"
it should "verify the deserialization of the store api" in { it should "verify the deserialization of the store api" in {
val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json") val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json")
val docs = ApiExtractor.extractApiOperations("src/test/resources/petstore", resourceListing.apis) val docs = ApiExtractor.extractApiOperations("src/test/resources/petstore", resourceListing.apis)
val m = docs.map(t => (t.resourcePath, t)).toMap val m = docs.map(t => (t.resourcePath, t)).toMap
val storeApi = m("/store") val storeApi = m("/store")
@ -68,7 +65,6 @@ class ApiExtractorTest extends FlatSpec with ShouldMatchers {
@RunWith(classOf[JUnitRunner]) @RunWith(classOf[JUnitRunner])
class CoreUtilsTest extends FlatSpec with ShouldMatchers { class CoreUtilsTest extends FlatSpec with ShouldMatchers {
val json = ScalaJsonUtil.getJsonMapper
sys.props += "fileMap" -> "src/test/resources/petstore" sys.props += "fileMap" -> "src/test/resources/petstore"
behavior of "CoreUtils" behavior of "CoreUtils"