mirror of
https://github.com/valitydev/openapi-generator.git
synced 2024-11-08 11:23:58 +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
|
||||
|
||||
{{#model}}
|
||||
class {{classname}} {
|
||||
case class {{classname}} (
|
||||
{{#vars}}
|
||||
|
||||
{{#notes}}/* {{notes}} */
|
||||
{{/notes}}
|
||||
{{#description}}/* {{description}} */
|
||||
{{/description}}
|
||||
@BeanProperty var {{name}}: {{datatype}} = {{defaultValue}}
|
||||
{{/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
|
||||
}
|
||||
}
|
||||
{{name}}: {{datatype}}{{#hasMore}},{{newline}} {{/hasMore}}
|
||||
{{/vars}})
|
||||
{{/model}}
|
||||
{{/models}}
|
@ -92,15 +92,36 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil {
|
||||
val operations = extractOperations(subDocs, allModels)
|
||||
val apiMap = groupApisToFiles(operations)
|
||||
|
||||
processApiMap(apiMap)
|
||||
processModelMap(allModels)
|
||||
val modelBundle = prepareModelBundle(allModels.toMap)
|
||||
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)
|
||||
}
|
||||
|
||||
def processModelMap(models: HashMap[String, DocumentationSchema]) = {
|
||||
val modelBundleList = new ListBuffer[Map[String, AnyRef]]
|
||||
for ((name, schema) <- models) {
|
||||
/**
|
||||
* creates a map of models and properties needed to write source
|
||||
*/
|
||||
def prepareModelBundle(models: Map[String, DocumentationSchema]): List[Map[String, AnyRef]] = {
|
||||
(for ((name, schema) <- models) yield {
|
||||
if (!defaultIncludes.contains(name)) {
|
||||
val m = new HashMap[String, AnyRef]
|
||||
m += "name" -> name
|
||||
@ -111,23 +132,21 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil {
|
||||
m += "invokerPackage" -> invokerPackage
|
||||
m += "outputDirectory" -> (destinationDir + File.separator + modelPackage.getOrElse("").replaceAll("\\.", File.separator))
|
||||
m += "newline" -> "\n"
|
||||
modelBundleList += m.toMap
|
||||
for ((file, suffix) <- modelTemplateFiles) {
|
||||
m += "filename" -> (name + suffix)
|
||||
generateAndWrite(m.toMap, file)
|
||||
}
|
||||
|
||||
Some(m.toMap)
|
||||
}
|
||||
}
|
||||
else None
|
||||
}).flatten.toList
|
||||
}
|
||||
|
||||
def processApiMap(apiMap: Map[(String, String), List[(String, DocumentationOperation)]] ) = {
|
||||
for ((identifier, operationList) <- apiMap) {
|
||||
def prepareApiBundle(apiMap: Map[(String, String), List[(String, DocumentationOperation)]] ): List[Map[String, AnyRef]] = {
|
||||
(for ((identifier, operationList) <- apiMap) yield {
|
||||
val basePath = identifier._1
|
||||
val name = identifier._2
|
||||
val className = toApiName(name)
|
||||
|
||||
val m = new HashMap[String, AnyRef]
|
||||
m += "name" -> name
|
||||
m += "name" -> toApiName(name)
|
||||
m += "className" -> className
|
||||
m += "basePath" -> basePath
|
||||
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 += "newline" -> "\n"
|
||||
|
||||
for ((file, suffix) <- apiTemplateFiles) {
|
||||
m += "filename" -> (className + suffix)
|
||||
generateAndWrite(m.toMap, file)
|
||||
Some(m.toMap)
|
||||
}).flatten.toList
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) = {
|
||||
|
@ -31,6 +31,13 @@ class BasicJavaGenerator extends BasicGenerator {
|
||||
"String",
|
||||
"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(
|
||||
"string" -> "String",
|
||||
"int" -> "Integer",
|
||||
@ -94,9 +101,8 @@ class BasicJavaGenerator extends BasicGenerator {
|
||||
val declaredType = dt.indexOf("[") match {
|
||||
case -1 => dt
|
||||
case n: Int => {
|
||||
if (dt.substring(0, n) == "Array") {
|
||||
if (dt.substring(0, n) == "Array")
|
||||
"List" + dt.substring(n).replaceAll("\\[", "<").replaceAll("\\]", ">")
|
||||
}
|
||||
else dt.replaceAll("\\[", "<").replaceAll("\\]", ">")
|
||||
}
|
||||
case _ => dt
|
||||
@ -128,14 +134,17 @@ class BasicJavaGenerator extends BasicGenerator {
|
||||
(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) = {
|
||||
dataType match {
|
||||
case "boolean" => "false"
|
||||
case "int" => "0"
|
||||
case "long" => "0L"
|
||||
case "float" => "0.0f"
|
||||
case "double" => "0.0"
|
||||
case "Boolean" => "null"
|
||||
case "Integer" => "null"
|
||||
case "Long" => "null"
|
||||
case "Float" => "null"
|
||||
case "Double" => "null"
|
||||
case "List" => {
|
||||
val inner = {
|
||||
if (obj.items.ref != null) obj.items.ref
|
||||
|
@ -106,7 +106,6 @@ abstract class CodegenConfig {
|
||||
}
|
||||
|
||||
def toDefaultValue(datatype: String, defaultValue: String): Option[String] = {
|
||||
|
||||
if (defaultValue != "" && defaultValue != null) {
|
||||
toDeclaredType(datatype) match {
|
||||
case "int" => Some(defaultValue)
|
||||
|
@ -16,7 +16,16 @@ import scala.reflect.BeanProperty
|
||||
class BasicGeneratorTest extends FlatSpec with ShouldMatchers {
|
||||
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"
|
||||
|
||||
@ -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.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")
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* classes
|
||||
|
@ -93,6 +93,25 @@ class BasicScalaGeneratorTest extends FlatSpec with ShouldMatchers {
|
||||
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
|
||||
* classes
|
||||
|
Loading…
Reference in New Issue
Block a user