mirror of
https://github.com/valitydev/openapi-generator.git
synced 2024-11-08 19:33:55 +00:00
refactored to make more testable
This commit is contained in:
parent
d6cf7fc9aa
commit
cec3fa5810
@ -7,25 +7,14 @@ package {{package}}
|
|||||||
import scala.reflect.BeanProperty
|
import scala.reflect.BeanProperty
|
||||||
|
|
||||||
{{#model}}
|
{{#model}}
|
||||||
class {{classname}} {
|
case class {{classname}} (
|
||||||
{{#vars}}
|
{{#vars}}
|
||||||
|
|
||||||
{{#notes}}/* {{notes}} */
|
{{#notes}}/* {{notes}} */
|
||||||
{{/notes}}
|
{{/notes}}
|
||||||
{{#description}}/* {{description}} */
|
{{#description}}/* {{description}} */
|
||||||
{{/description}}
|
{{/description}}
|
||||||
@BeanProperty var {{name}}: {{datatype}} = {{defaultValue}}
|
{{name}}: {{datatype}}{{#hasMore}},{{newline}} {{/hasMore}}
|
||||||
{{/vars}}
|
{{/vars}})
|
||||||
|
|
||||||
override def toString: String = {
|
|
||||||
val sb = new StringBuilder
|
|
||||||
sb.append("class {{classname}} {\n")
|
|
||||||
{{#vars}}
|
|
||||||
sb.append(" {{name}}: ").append({{name}}).append("\n")
|
|
||||||
{{/vars}}
|
|
||||||
sb.append("}\n")
|
|
||||||
sb.toString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{/model}}
|
{{/model}}
|
||||||
{{/models}}
|
{{/models}}
|
@ -92,15 +92,36 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil {
|
|||||||
val operations = extractOperations(subDocs, allModels)
|
val operations = extractOperations(subDocs, allModels)
|
||||||
val apiMap = groupApisToFiles(operations)
|
val apiMap = groupApisToFiles(operations)
|
||||||
|
|
||||||
processApiMap(apiMap)
|
val modelBundle = prepareModelBundle(allModels.toMap)
|
||||||
processModelMap(allModels)
|
val modelFiles = bundleToSource(modelBundle, modelTemplateFiles.toMap)
|
||||||
|
|
||||||
|
modelFiles.map(m => {
|
||||||
|
val filename = m._1
|
||||||
|
val fw = new FileWriter(filename, false)
|
||||||
|
fw.write(m._2 + "\n")
|
||||||
|
fw.close()
|
||||||
|
println("wrote model " + filename)
|
||||||
|
})
|
||||||
|
|
||||||
|
val apiBundle = prepareApiBundle(apiMap.toMap)
|
||||||
|
val apiFiles = bundleToSource(apiBundle, apiTemplateFiles.toMap)
|
||||||
|
|
||||||
|
apiFiles.map(m => {
|
||||||
|
val filename = m._1
|
||||||
|
val fw = new FileWriter(filename, false)
|
||||||
|
fw.write(m._2 + "\n")
|
||||||
|
fw.close()
|
||||||
|
println("wrote api " + filename)
|
||||||
|
})
|
||||||
|
|
||||||
codegen.writeSupportingClasses(apiMap.toMap, allModels.toMap)
|
codegen.writeSupportingClasses(apiMap.toMap, allModels.toMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
def processModelMap(models: HashMap[String, DocumentationSchema]) = {
|
/**
|
||||||
val modelBundleList = new ListBuffer[Map[String, AnyRef]]
|
* creates a map of models and properties needed to write source
|
||||||
for ((name, schema) <- models) {
|
*/
|
||||||
|
def prepareModelBundle(models: Map[String, DocumentationSchema]): List[Map[String, AnyRef]] = {
|
||||||
|
(for ((name, schema) <- models) yield {
|
||||||
if (!defaultIncludes.contains(name)) {
|
if (!defaultIncludes.contains(name)) {
|
||||||
val m = new HashMap[String, AnyRef]
|
val m = new HashMap[String, AnyRef]
|
||||||
m += "name" -> name
|
m += "name" -> name
|
||||||
@ -111,23 +132,21 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil {
|
|||||||
m += "invokerPackage" -> invokerPackage
|
m += "invokerPackage" -> invokerPackage
|
||||||
m += "outputDirectory" -> (destinationDir + File.separator + modelPackage.getOrElse("").replaceAll("\\.", File.separator))
|
m += "outputDirectory" -> (destinationDir + File.separator + modelPackage.getOrElse("").replaceAll("\\.", File.separator))
|
||||||
m += "newline" -> "\n"
|
m += "newline" -> "\n"
|
||||||
modelBundleList += m.toMap
|
|
||||||
for ((file, suffix) <- modelTemplateFiles) {
|
Some(m.toMap)
|
||||||
m += "filename" -> (name + suffix)
|
|
||||||
generateAndWrite(m.toMap, file)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else None
|
||||||
|
}).flatten.toList
|
||||||
}
|
}
|
||||||
|
|
||||||
def processApiMap(apiMap: Map[(String, String), List[(String, DocumentationOperation)]] ) = {
|
def prepareApiBundle(apiMap: Map[(String, String), List[(String, DocumentationOperation)]] ): List[Map[String, AnyRef]] = {
|
||||||
for ((identifier, operationList) <- apiMap) {
|
(for ((identifier, operationList) <- apiMap) yield {
|
||||||
val basePath = identifier._1
|
val basePath = identifier._1
|
||||||
val name = identifier._2
|
val name = identifier._2
|
||||||
val className = toApiName(name)
|
val className = toApiName(name)
|
||||||
|
|
||||||
val m = new HashMap[String, AnyRef]
|
val m = new HashMap[String, AnyRef]
|
||||||
m += "name" -> name
|
m += "name" -> toApiName(name)
|
||||||
m += "className" -> className
|
m += "className" -> className
|
||||||
m += "basePath" -> basePath
|
m += "basePath" -> basePath
|
||||||
m += "package" -> apiPackage
|
m += "package" -> apiPackage
|
||||||
@ -137,11 +156,21 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil {
|
|||||||
m += "outputDirectory" -> (destinationDir + File.separator + apiPackage.getOrElse("").replaceAll("\\.", File.separator))
|
m += "outputDirectory" -> (destinationDir + File.separator + apiPackage.getOrElse("").replaceAll("\\.", File.separator))
|
||||||
m += "newline" -> "\n"
|
m += "newline" -> "\n"
|
||||||
|
|
||||||
for ((file, suffix) <- apiTemplateFiles) {
|
Some(m.toMap)
|
||||||
m += "filename" -> (className + suffix)
|
}).flatten.toList
|
||||||
generateAndWrite(m.toMap, file)
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* turns a bundle into source files with output file name
|
||||||
|
*/
|
||||||
|
def bundleToSource(bundle:List[Map[String, AnyRef]], templates: Map[String, String]): List[(String, String)] = {
|
||||||
|
val output = new ListBuffer[(String, String)]
|
||||||
|
bundle.foreach(m => {
|
||||||
|
for ((file, suffix) <- templates) {
|
||||||
|
output += Tuple2(m("outputDirectory").toString + File.separator + m("name").toString + suffix, codegen.generateSource(m, file))
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
output.toList
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateAndWrite(bundle: Map[String, AnyRef], templateFile: String) = {
|
def generateAndWrite(bundle: Map[String, AnyRef], templateFile: String) = {
|
||||||
|
@ -31,6 +31,13 @@ class BasicJavaGenerator extends BasicGenerator {
|
|||||||
"String",
|
"String",
|
||||||
"boolean")
|
"boolean")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We are using java objects instead of primitives to avoid showing default
|
||||||
|
* primitive values when the API returns missing data. For instance, having a
|
||||||
|
* {"count":0} != count is unknown. You can change this to use primitives if you
|
||||||
|
* desire, but update the default values as well or they'll be set to null in
|
||||||
|
* variable declarations.
|
||||||
|
*/
|
||||||
override def typeMapping = Map(
|
override def typeMapping = Map(
|
||||||
"string" -> "String",
|
"string" -> "String",
|
||||||
"int" -> "Integer",
|
"int" -> "Integer",
|
||||||
@ -94,9 +101,8 @@ class BasicJavaGenerator extends BasicGenerator {
|
|||||||
val declaredType = dt.indexOf("[") match {
|
val declaredType = dt.indexOf("[") match {
|
||||||
case -1 => dt
|
case -1 => dt
|
||||||
case n: Int => {
|
case n: Int => {
|
||||||
if (dt.substring(0, n) == "Array") {
|
if (dt.substring(0, n) == "Array")
|
||||||
"List" + dt.substring(n).replaceAll("\\[", "<").replaceAll("\\]", ">")
|
"List" + dt.substring(n).replaceAll("\\[", "<").replaceAll("\\]", ">")
|
||||||
}
|
|
||||||
else dt.replaceAll("\\[", "<").replaceAll("\\]", ">")
|
else dt.replaceAll("\\[", "<").replaceAll("\\]", ">")
|
||||||
}
|
}
|
||||||
case _ => dt
|
case _ => dt
|
||||||
@ -128,14 +134,17 @@ class BasicJavaGenerator extends BasicGenerator {
|
|||||||
(declaredType, defaultValue)
|
(declaredType, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// default values
|
/**
|
||||||
|
* we are defaulting to null values since the codegen uses java objects instead of primitives
|
||||||
|
* If you change to primitives, you can put in the appropriate values (0.0f, etc).
|
||||||
|
*/
|
||||||
override def toDefaultValue(dataType: String, obj: DocumentationSchema) = {
|
override def toDefaultValue(dataType: String, obj: DocumentationSchema) = {
|
||||||
dataType match {
|
dataType match {
|
||||||
case "boolean" => "false"
|
case "Boolean" => "null"
|
||||||
case "int" => "0"
|
case "Integer" => "null"
|
||||||
case "long" => "0L"
|
case "Long" => "null"
|
||||||
case "float" => "0.0f"
|
case "Float" => "null"
|
||||||
case "double" => "0.0"
|
case "Double" => "null"
|
||||||
case "List" => {
|
case "List" => {
|
||||||
val inner = {
|
val inner = {
|
||||||
if (obj.items.ref != null) obj.items.ref
|
if (obj.items.ref != null) obj.items.ref
|
||||||
|
@ -106,7 +106,6 @@ abstract class CodegenConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def toDefaultValue(datatype: String, defaultValue: String): Option[String] = {
|
def toDefaultValue(datatype: String, defaultValue: String): Option[String] = {
|
||||||
|
|
||||||
if (defaultValue != "" && defaultValue != null) {
|
if (defaultValue != "" && defaultValue != null) {
|
||||||
toDeclaredType(datatype) match {
|
toDeclaredType(datatype) match {
|
||||||
case "int" => Some(defaultValue)
|
case "int" => Some(defaultValue)
|
||||||
|
@ -16,7 +16,16 @@ import scala.reflect.BeanProperty
|
|||||||
class BasicGeneratorTest extends FlatSpec with ShouldMatchers {
|
class BasicGeneratorTest extends FlatSpec with ShouldMatchers {
|
||||||
val json = ScalaJsonUtil.getJsonMapper
|
val json = ScalaJsonUtil.getJsonMapper
|
||||||
|
|
||||||
class SampleGenerator extends BasicGenerator
|
class SampleGenerator extends BasicGenerator {
|
||||||
|
modelTemplateFiles += "model.mustache" -> ".test"
|
||||||
|
override def typeMapping = Map(
|
||||||
|
"string" -> "String",
|
||||||
|
"int" -> "Int",
|
||||||
|
"float" -> "Float",
|
||||||
|
"long" -> "Long",
|
||||||
|
"double" -> "Double",
|
||||||
|
"object" -> "Any")
|
||||||
|
}
|
||||||
|
|
||||||
behavior of "BasicGenerator"
|
behavior of "BasicGenerator"
|
||||||
|
|
||||||
@ -73,4 +82,79 @@ class BasicGeneratorTest extends FlatSpec with ShouldMatchers {
|
|||||||
(orderOperations.map(m => m.httpMethod).toSet & Set("GET", "DELETE")).size should be (2)
|
(orderOperations.map(m => m.httpMethod).toSet & Set("GET", "DELETE")).size should be (2)
|
||||||
(orderOperations.map(m => m.nickname).toSet & Set("getOrderById", "deleteOrder")).size should be (2)
|
(orderOperations.map(m => m.nickname).toSet & Set("getOrderById", "deleteOrder")).size should be (2)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
it should "create a model map" in {
|
||||||
|
implicit val basePath = "http://localhost:8080/api"
|
||||||
|
val generator = new SampleGenerator
|
||||||
|
val model = getSampleModel
|
||||||
|
|
||||||
|
val bundle = generator.prepareModelBundle(Map(model.id -> model)).head
|
||||||
|
|
||||||
|
// inspect properties
|
||||||
|
bundle("name") should be ("SampleObject")
|
||||||
|
bundle("className") should be ("SampleObject")
|
||||||
|
bundle("invokerPackage") should be (Some("com.wordnik.client.common"))
|
||||||
|
bundle("package") should be (Some("com.wordnik.client.model"))
|
||||||
|
|
||||||
|
// inspect models
|
||||||
|
val modelList = bundle("models").asInstanceOf[List[(String, DocumentationSchema)]]
|
||||||
|
modelList.size should be (1)
|
||||||
|
modelList.head._1 should be ("SampleObject")
|
||||||
|
modelList.head._2.getClass should be (classOf[DocumentationSchema])
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "create a model file" in {
|
||||||
|
implicit val basePath = "http://localhost:8080/api"
|
||||||
|
val generator = new SampleGenerator
|
||||||
|
|
||||||
|
val model = getSampleModel
|
||||||
|
val bundle = generator.prepareModelBundle(Map(model.id -> model))
|
||||||
|
val modelFile = generator.bundleToSource(bundle, generator.modelTemplateFiles.toMap).head
|
||||||
|
// modelFile._1 should be ("SampleObject.test")
|
||||||
|
|
||||||
|
val fileContents = modelFile._2
|
||||||
|
fileContents.indexOf("case class SampleObject") should not be (-1)
|
||||||
|
fileContents.indexOf("longValue: Long") should not be (-1)
|
||||||
|
fileContents.indexOf("intValue: Int") should not be (-1)
|
||||||
|
fileContents.indexOf("doubleValue: Double") should not be (-1)
|
||||||
|
fileContents.indexOf("stringValue: String") should not be (-1)
|
||||||
|
fileContents.indexOf("floatValue: Float") should not be (-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def getSampleModel = {
|
||||||
|
val model = new DocumentationSchema
|
||||||
|
model.id = "SampleObject"
|
||||||
|
model.name = "SampleObject"
|
||||||
|
model.properties = {
|
||||||
|
val list = new HashMap[String, DocumentationSchema]
|
||||||
|
|
||||||
|
val stringProperty = new DocumentationSchema
|
||||||
|
stringProperty.name = "stringValue"
|
||||||
|
stringProperty.setType("string")
|
||||||
|
list += "stringValue" -> stringProperty
|
||||||
|
|
||||||
|
val intProperty = new DocumentationSchema
|
||||||
|
intProperty.name = "intValue"
|
||||||
|
intProperty.setType("int")
|
||||||
|
list += "intValue" -> intProperty
|
||||||
|
|
||||||
|
val longProperty = new DocumentationSchema
|
||||||
|
longProperty.name = "longValue"
|
||||||
|
longProperty.setType("long")
|
||||||
|
list += "longValue" -> longProperty
|
||||||
|
|
||||||
|
val floatProperty = new DocumentationSchema
|
||||||
|
floatProperty.name = "floatValue"
|
||||||
|
floatProperty.setType("float")
|
||||||
|
list += "floatValue" -> floatProperty
|
||||||
|
|
||||||
|
val doubleProperty = new DocumentationSchema
|
||||||
|
doubleProperty.name = "doubleValue"
|
||||||
|
doubleProperty.setType("double")
|
||||||
|
list += "doubleValue" -> doubleProperty
|
||||||
|
|
||||||
|
list.asJava
|
||||||
|
}
|
||||||
|
model
|
||||||
|
}
|
||||||
|
}
|
@ -93,6 +93,26 @@ class BasicJavaGeneratorTest extends FlatSpec with ShouldMatchers {
|
|||||||
config.toDeclaredType("object") should be ("Object")
|
config.toDeclaredType("object") should be ("Object")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* declarations are used in models, and types need to be
|
||||||
|
* mapped appropriately
|
||||||
|
*/
|
||||||
|
it should "convert a string a declaration" in {
|
||||||
|
val expected = Map(
|
||||||
|
"string" -> ("String", "null"),
|
||||||
|
"int" -> ("Integer", "null"),
|
||||||
|
"float" -> ("Float", "null"),
|
||||||
|
"long" -> ("Long", "null"),
|
||||||
|
"double" -> ("Double", "null"),
|
||||||
|
"object" -> ("Object", "null"))
|
||||||
|
expected.map(e => {
|
||||||
|
val model = new DocumentationSchema
|
||||||
|
model.name = "simple_" + e._1
|
||||||
|
model.setType(e._1)
|
||||||
|
config.toDeclaration(model) should be (e._2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* codegen should honor special imports to avoid generating
|
* codegen should honor special imports to avoid generating
|
||||||
* classes
|
* classes
|
||||||
|
@ -93,6 +93,25 @@ class BasicScalaGeneratorTest extends FlatSpec with ShouldMatchers {
|
|||||||
config.toDeclaredType("object") should be ("Any")
|
config.toDeclaredType("object") should be ("Any")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* declarations are used in models, and types need to be
|
||||||
|
* mapped appropriately
|
||||||
|
*/
|
||||||
|
it should "convert a string a declaration" in {
|
||||||
|
val expected = Map("string" -> ("String", "_"),
|
||||||
|
"int" -> ("Int", "0"),
|
||||||
|
"float" -> ("Float", "0f"),
|
||||||
|
"long" -> ("Long", "0L"),
|
||||||
|
"double" -> ("Double", "0.0"),
|
||||||
|
"object" -> ("Any", "_"))
|
||||||
|
expected.map(e => {
|
||||||
|
val model = new DocumentationSchema
|
||||||
|
model.name = "simple_" + e._1
|
||||||
|
model.setType(e._1)
|
||||||
|
config.toDeclaration(model) should be (e._2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* codegen should honor special imports to avoid generating
|
* codegen should honor special imports to avoid generating
|
||||||
* classes
|
* classes
|
||||||
|
Loading…
Reference in New Issue
Block a user