diff --git a/README.md b/README.md index df7082a..44cf6dc 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,15 @@ [![License](https://img.shields.io/github/license/eikek/sbt-openapi-schema.svg?style=flat-square&color=steelblue)](https://github.com/eikek/sbt-openapi-schema/blob/master/LICENSE.txt) -This is an sbt plugin to generate Scala, Java or Elm code given an -openapi 3.x specification. Unlike other codegen tools, this focuses -only on the `#/components/schema` section. Also, it generates -immutable classes and optionally the corresponding JSON conversions. +This is an sbt plugin to generate Scala or Elm code given an openapi +3.x specification. Unlike other codegen tools, this focuses only on +the `#/components/schema` section. Also, it generates immutable +classes and optionally the corresponding JSON conversions. - Scala: `case class`es are generated and JSON conversion via circe. -- Java: immutable classes (with builder pattern) are generated and - JSON conversion via jackson (requires jackson > 2.9). -- Elm: (experimental) records are generated and constructors for - "empty" values. It works only for objects. JSON conversion is - generated using Elm's default encoding support and the +- Elm: records are generated and constructors for "empty" values. It + works only for objects. JSON conversion is generated using Elm's + default encoding support and the [json-decode-pipeline](https://github.com/NoRedInk/elm-json-decode-pipeline) module for decoding. - JSON support is optional. @@ -63,27 +61,25 @@ from the `compile` task. ## Configuration The configuration is specific to the target language. There exists a -separate configuration object for Java, Scala and Elm. +separate configuration object for Scala and Elm. -The key `openapiJavaConfig` and `openapiScalaConfig` define some -configuration to customize the code generation. +The key `openapiScalaConfig` defines some configuration to customize +the code generation. -For Java, it looks like this: +For Scala, it looks like this: ```scala -case class JavaConfig(mapping: CustomMapping = CustomMapping.none - , json: JavaJson = JavaJson.none - , builderParents: List[Superclass] = Nil) { +case class ScalaConfig( + mapping: CustomMapping = CustomMapping.none, + json: ScalaJson = ScalaJson.none +) { - def withJson(json: JavaJson): JavaConfig = + def withJson(json: ScalaJson): ScalaConfig = copy(json = json) - def addBuilderParent(sc: Superclass): JavaConfig = - copy(builderParents = sc :: builderParents) - - def addMapping(cm: CustomMapping): JavaConfig = + def addMapping(cm: CustomMapping): ScalaConfig = copy(mapping = mapping.andThen(cm)) - def setMapping(cm: CustomMapping): JavaConfig = + def setMapping(cm: CustomMapping): ScalaConfig = copy(mapping = cm) } ``` @@ -92,12 +88,13 @@ By default, no JSON support is added to the generated classes. This can be changed via: ``` -openapiJavaConfig := JavaConfig.default.withJson(JavaJson.jackson) +openapiScalaConfig := ScalaConfig().withJson(ScalaJson.circeSemiauto) ``` -This generates the required annotations for jackson. Note, that this -plugin doesn't change your `libraryDependencies` setting. So you need -to add the jackson dependency yourself. +This generates the encoder and decoder using +[circe](https://github.com/circe/circe). Note, that this plugin +doesn't change your `libraryDependencies` setting. So you need to add +the circe dependencies yourself. The `CustomMapping` class allows to change the class names or use different types (for example, you might want to change `LocalDate` to @@ -129,22 +126,27 @@ file. Here is a `build.sbt` example snippet: ```scala import com.github.eikek.sbt.openapi._ +val CirceVersion = "0.14.1" libraryDependencies ++= Seq( - "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.8", - "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.9.8" + "io.circe" %% "circe-generic" % CirceVersion, + "io.circe" %% "circe-parser" % CirceVersion ) openapiSpec := (Compile/resourceDirectory).value/"test.yml" -openapiTargetLanguage := Language.Java -Compile/openapiJavaConfig := JavaConfig.default. - withJson(JavaJson.jackson). - addMapping(CustomMapping.forName({ case s => s + "Dto" })) +openapiTargetLanguage := Language.Scala +Compile/openapiScalaConfig := ScalaConfig() + .withJson(ScalaJson.circeSemiauto) + .addMapping(CustomMapping.forType({ case TypeDef("LocalDateTime", _) => + TypeDef("Timestamp", Imports("com.mypackage.Timestamp")) + })) + .addMapping(CustomMapping.forName({ case s => s + "Dto" })) enablePlugins(OpenApiSchema) ``` -It adds jackson JSON support and changes the name of all classes by -appending the suffix "Dto". +It adds circe JSON support and changes the name of all classes by +appending the suffix "Dto". It also changes the type used for local +dates to be `com.mypackage.Timestamp`. ## Elm @@ -193,12 +195,12 @@ list along with the main source dir. It may look something like this: It always generates type aliases for records. -While source files for scala and java are added to sbt's -`sourceGenerators` so that they get compiled with your sources, the -elm source files are not added anywhere, because there is no support -for Elm in sbt. However, in the `build.sbt` file, you can tell sbt to -generate the files before compiling your elm app. This can be -configured to run during resource generation. Example: +While source files for scala are added to sbt's `sourceGenerators` so +that they get compiled with your sources, the elm source files are not +added anywhere, because there is no support for Elm in sbt. However, +in the `build.sbt` file, you can tell sbt to generate the files before +compiling your elm app. This can be configured to run during resource +generation. Example: ``` scala @@ -461,16 +463,6 @@ lint`](https://redoc.ly/docs/cli/) against your specification file. This also requires to have nodejs installed. -## TODOs - -- support validation - - openapi has several validation definitions - - (java) support bean validation -- convert markdown description into html -- add unit tests -- add more integration tests - - see [Testing SBT Plugins](https://www.scala-sbt.org/1.x/docs/Testing-sbt-plugins.html) - - see `plugin/src/sbt-test/*` ## Credits diff --git a/plugin/src/main/scala/com/github/eikek/sbt/openapi/JavaConfig.scala b/plugin/src/main/scala/com/github/eikek/sbt/openapi/JavaConfig.scala deleted file mode 100644 index 1837bd6..0000000 --- a/plugin/src/main/scala/com/github/eikek/sbt/openapi/JavaConfig.scala +++ /dev/null @@ -1,26 +0,0 @@ -package com.github.eikek.sbt.openapi - -case class JavaConfig( - mapping: CustomMapping = CustomMapping.none, - json: JavaJson = JavaJson.none, - builderParents: List[Superclass] = Nil -) { - - def withJson(json: JavaJson): JavaConfig = - copy(json = json) - - def addBuilderParent(sc: Superclass): JavaConfig = - copy(builderParents = sc :: builderParents) - - def addMapping(cm: CustomMapping): JavaConfig = - copy(mapping = mapping.andThen(cm)) - - def setMapping(cm: CustomMapping): JavaConfig = - copy(mapping = cm) -} - -object JavaConfig { - - val default = JavaConfig() - -} diff --git a/plugin/src/main/scala/com/github/eikek/sbt/openapi/JavaJson.scala b/plugin/src/main/scala/com/github/eikek/sbt/openapi/JavaJson.scala deleted file mode 100644 index 801f4e5..0000000 --- a/plugin/src/main/scala/com/github/eikek/sbt/openapi/JavaJson.scala +++ /dev/null @@ -1,68 +0,0 @@ -package com.github.eikek.sbt.openapi - -trait JavaJson { - - def resolve(src: SourceFile): SourceFile - - def builderAnnotations(src: SourceFile): List[Annotation] - -} - -object JavaJson { - val none = new JavaJson { - def resolve(src: SourceFile): SourceFile = src - def builderAnnotations(src: SourceFile): List[Annotation] = Nil - } - - val jackson = new JavaJson { - - def jacksonDeserializer(src: SourceFile) = - Annotation(s"@JsonDeserialize(builder = ${src.name}.Builder.class)") - def jacksonIgnore(src: SourceFile) = { - val props = src.fields - .map(_.prop) - .filter(_.nullable) - .map(_.name) - .map(n => "\"" + n + "Optional\"") - .mkString(", ") - Annotation(s"@JsonIgnoreProperties({ $props })") - } - def jacksonAutoDetect = - Annotation("@JsonAutoDetect(getterVisibility = Visibility.NON_PRIVATE)") - - val jackonBuilderPojo = - Annotation("@JsonPOJOBuilder(withPrefix = \"set\")") - - def resolve(src: SourceFile): SourceFile = - if (src.wrapper) { - src - .addImports( - Imports( - "com.fasterxml.jackson.annotation.JsonValue", - "com.fasterxml.jackson.annotation.JsonCreator" - ) - ) - .copy(fields = - src.fields.map(f => Field(f.prop, List(Annotation("@JsonValue")), f.typeDef)) - ) - .addCtorAnnotation(Annotation("@JsonCreator")) - } else { - src - .addAnnotation(jacksonDeserializer(src)) - .addAnnotation(jacksonIgnore(src)) - .addAnnotation(jacksonAutoDetect) - .addImports( - Imports( - "com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder", - "com.fasterxml.jackson.databind.annotation.JsonDeserialize", - "com.fasterxml.jackson.annotation.JsonIgnoreProperties", - "com.fasterxml.jackson.annotation.JsonAutoDetect", - "com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility" - ) - ) - } - - def builderAnnotations(src: SourceFile): List[Annotation] = - List(jackonBuilderPojo) - } -} diff --git a/plugin/src/main/scala/com/github/eikek/sbt/openapi/OpenApiSchema.scala b/plugin/src/main/scala/com/github/eikek/sbt/openapi/OpenApiSchema.scala index 2360ce0..3564195 100644 --- a/plugin/src/main/scala/com/github/eikek/sbt/openapi/OpenApiSchema.scala +++ b/plugin/src/main/scala/com/github/eikek/sbt/openapi/OpenApiSchema.scala @@ -15,7 +15,6 @@ object OpenApiSchema extends AutoPlugin { def extension: String = productPrefix.toLowerCase } object Language { - case object Java extends Language case object Scala extends Language case object Elm extends Language } @@ -28,13 +27,11 @@ object OpenApiSchema extends AutoPlugin { val openapiSpec = settingKey[File]("The openapi specification") val openapiPackage = settingKey[Pkg]("The package to place the generated files into") - val openapiJavaConfig = - settingKey[JavaConfig]("Configuration for generating java files") val openapiScalaConfig = settingKey[ScalaConfig]("Configuration for generating scala files") val openapiElmConfig = settingKey[ElmConfig]("Configuration for generating elm files") val openapiTargetLanguage = - settingKey[Language]("The target language: either Language.Scala or Language.Java.") + settingKey[Language]("The target language: either Language.Scala or Language.Elm.") val openapiOutput = settingKey[File]("The directory where files are generated") val openapiCodegen = taskKey[Seq[File]]("Run the code generation") val openapiStaticDoc = taskKey[File]("Generate a static HTML documentation") @@ -52,7 +49,6 @@ object OpenApiSchema extends AutoPlugin { val defaultSettings = Seq( openapiPackage := Pkg("org.myapi"), - openapiJavaConfig := JavaConfig(), openapiScalaConfig := ScalaConfig(), openapiElmConfig := ElmConfig(), openapiOutput := { @@ -64,13 +60,12 @@ object OpenApiSchema extends AutoPlugin { openapiCodegen := { val out = openapiOutput.value val logger = streams.value.log - val cfgJava = openapiJavaConfig.value val cfgScala = openapiScalaConfig.value val cfgElm = openapiElmConfig.value val spec = openapiSpec.value val pkg = openapiPackage.value val lang = openapiTargetLanguage.value - generateCode(logger, out, lang, cfgJava, cfgScala, cfgElm, spec, pkg) + generateCode(logger, out, lang, cfgScala, cfgElm, spec, pkg) }, openapiStaticOut := (Compile / resourceManaged).value / "openapiDoc", openapiStaticGen := OpenApiDocGenerator.Swagger, @@ -100,7 +95,6 @@ object OpenApiSchema extends AutoPlugin { logger: Logger, out: File, lang: Language, - cfgJava: JavaConfig, cfgScala: ScalaConfig, cfgElm: ElmConfig, spec: File, @@ -115,11 +109,9 @@ object OpenApiSchema extends AutoPlugin { val files = groupedSchemas.map { sc => val (name, code) = (lang, sc) match { - case (Language.Scala, _) => ScalaCode.generate(sc, pkg, cfgScala) - case (Language.Java, _: SingularSchemaClass) => - JavaCode.generate(sc, pkg, cfgJava) + case (Language.Scala, _) => ScalaCode.generate(sc, pkg, cfgScala) case (Language.Elm, _: SingularSchemaClass) => ElmCode.generate(sc, pkg, cfgElm) - case _ => sys.error(s"Java and Elm not yet supported for discriminants") + case _ => sys.error(s"Elm not yet supported for discriminants") } val file = targetPath / (name + "." + lang.extension) if (!file.exists || IO.read(file) != code) { diff --git a/plugin/src/main/scala/com/github/eikek/sbt/openapi/impl/JavaCode.scala b/plugin/src/main/scala/com/github/eikek/sbt/openapi/impl/JavaCode.scala deleted file mode 100644 index c537201..0000000 --- a/plugin/src/main/scala/com/github/eikek/sbt/openapi/impl/JavaCode.scala +++ /dev/null @@ -1,281 +0,0 @@ -package com.github.eikek.sbt.openapi.impl - -import com.github.eikek.sbt.openapi.PartConv._ -import com.github.eikek.sbt.openapi._ - -object JavaCode { - - val primitiveTypeMapping: TypeMapping = - TypeMapping( - Type.Bool -> TypeDef("boolean", Imports.empty), - Type.String -> TypeDef("String", Imports.empty), - Type.Int32 -> TypeDef("int", Imports.empty), - Type.Int64 -> TypeDef("long", Imports.empty), - Type.Float32 -> TypeDef("float", Imports.empty), - Type.Float64 -> TypeDef("double", Imports.empty), - Type.Uuid -> TypeDef("UUID", Imports("java.util.UUID")), - Type.Url -> TypeDef("URL", Imports("java.net.URL")), - Type.Uri -> TypeDef("URI", Imports("java.net.URI")), - Type.Date(Type.TimeRepr.String) -> TypeDef( - "LocalDate", - Imports("java.time.LocalDate") - ), - Type.Date(Type.TimeRepr.Number) -> TypeDef( - "LocalDate", - Imports("java.time.LocalDate") - ), - Type.DateTime(Type.TimeRepr.String) -> TypeDef( - "LocalDateTime", - Imports("java.time.LocalDateTime") - ), - Type.DateTime(Type.TimeRepr.Number) -> TypeDef( - "LocalDateTime", - Imports("java.time.LocalDateTime") - ) - ) - - def boxed(td: TypeDef): TypeDef = td match { - case TypeDef("boolean", is) => TypeDef("Boolean", is) - case TypeDef("int", is) => TypeDef("Integer", is) - case TypeDef("long", is) => TypeDef("Long", is) - case TypeDef("float", is) => TypeDef("Float", is) - case TypeDef("double", is) => TypeDef("Double", is) - case _ => td - } - - def defaultTypeMapping(cm: CustomMapping): TypeMapping = { - case Type.Sequence(param) => - defaultTypeMapping(cm)(param).map(el => - cm.changeType( - TypeDef(s"List<${boxed(el).name}>", el.imports ++ Imports("java.util.List")) - ) - ) - case Type.Map(key, value) => - for { - k <- defaultTypeMapping(cm)(key) - v <- defaultTypeMapping(cm)(value) - } yield cm.changeType( - TypeDef( - s"Map<${boxed(k).name},${boxed(v).name}>", - k.imports ++ v.imports ++ Imports("java.util.Map") - ) - ) - case Type.Ref(name) => - val schema = SingularSchemaClass(name) - Some(TypeDef(resolveSchema(schema, cm).name, Imports.empty)) - case t => - primitiveTypeMapping(t).map(cm.changeType) - } - - object BuilderClass { - def builderMethod: PartConv[SourceFile] = - constant[SourceFile]("public static Builder newBuilder() {") ++ - constant("return new Builder();").map(_.indent(2)) ++ - constant("}") - - def apply(cfg: JavaConfig): PartConv[SourceFile] = - PartConv(src => if (src.wrapper) Part.empty else make(cfg).toPart(src)) - - def make(cfg: JavaConfig): PartConv[SourceFile] = - builderMethod.map(_.newline) ++ - forList(annotation, _ ++ _).contramap(s => cfg.json.builderAnnotations(s)) ++ - constant("public static final class Builder") ~ DataClass.parents - .contramap[SourceFile](_ => cfg.builderParents) ~ constant("{") ++ - DataClass - .fieldDeclaration("private") - .map(_.indent(2).newline) - .contramap(_.fields) ++ - build.map(_.indent(2).newline) ++ - forList(setter, _ ++ _).map(_.indent(2)).contramap(_.fields) ++ constant("}") - - def build: PartConv[SourceFile] = - constant("public") ~ string.contramap[SourceFile](_.name) ~ constant("build() {") ++ - constant("return new").map(_.indent(2)) ~ string.contramap(_.name) + constant( - "(" - ) + - DataClass.fieldNameList.contramap(_.fields) + constant(");") ++ - constant("}") - - def setter: PartConv[Field] = - doc.contramap[Field](_.prop.doc) ++ - constant("public Builder set") + fieldName.map(_.capitalize) + constant( - "(" - ) + DataClass.fieldType ~ - constant("value) {") ++ constant("this.").map(_.indent(2)) + fieldName ~ constant( - " = value;" - ) ++ - constant("return this;").map(_.indent(2)) ++ - constant("}").map(_.newline) - } - - object DataClass { - def apply(tm: TypeMapping, cfg: JavaConfig): PartConv[SourceFile] = - forList(annotation, _ ++ _).contramap[SourceFile](_.annot) ++ - constant("public final class") ~ sourceName ~ parents.contramap[SourceFile]( - _.parents - ) ~ constant("{") ++ - fieldDeclaration("private final") - .map(_.indent(2).newline) - .contramap[SourceFile](_.fields) ++ - constructor.map(_.indent(2).newline) ++ - forList(getter, _ ++ _).map(_.indent(2).newline).contramap(_.fields) ++ - setter ++ - equals.map(_.newline) ++ - hashcode.map(_.indent(2).newline) ++ - tostring.map(_.indent(2).newline) ++ - BuilderClass(cfg).map(_.indent(2)) ++ constant("}") - - def parents: PartConv[List[Superclass]] = - listSplit( - constant("extends") ~ superclass, - constant("implements") ~ forListSep(superclass, Part(", ")) - ) - - def fieldType: PartConv[Field] = PartConv { f => - if (f.prop.nullable) Part(boxed(f.typeDef).name) else Part(f.typeDef.name) - } - - def fieldDeclaration(modifier: String): PartConv[List[Field]] = { - val pc: PartConv[Field] = - forList(annotation, _ ++ _).contramap[Field](_.annot) ++ - constant(modifier) ~ fieldType ~ string - .contramap[Field](_.prop.name) - .map(_.semicolon) - - forList(pc, _ ++ _) - } - - def constructor: PartConv[SourceFile] = - forList(annotation, _ ++ _).contramap[SourceFile](_.ctorAnnot) ++ - constant("public") ~ string.contramap[SourceFile](_.name) + constant("(") + - typeNameList.contramap(_.fields) + constant(") {") ++ - fieldAssignList.contramap[SourceFile](_.fields).map(_.indent(2)) ++ constant("}") - - def getter: PartConv[Field] = { - val fg = - fieldType ~ cond(_.prop.`type` == Type.Bool, constant("is"), constant("get")) + - fieldName.map(_.capitalize) + constant("() {") ++ - constant("return this.").map(_.indent(2)) + fieldName.map(_.semicolon) ++ - constant("}").map(_.newline) - - val opt = doc.contramap[Field](_.prop.doc) ++ constant( - "public Optional<" - ) + fieldType + constant(">") ~ - cond(_.prop.`type` == Type.Bool, constant("is"), constant("get")) + - fieldName.map(_.capitalize) + constant("Optional() {") ++ - constant("return Optional.ofNullable(this.").map( - _.indent(2) - ) + fieldName + constant(");") ++ - constant("}").map(_.newline) - - cond[Field]( - _.prop.nullable, - fg ++ opt, - doc.contramap[Field](_.prop.doc) ++ constant("public") ~ fg - ) - } - - def setter: PartConv[SourceFile] = PartConv { sc => - def withMethod: PartConv[Field] = - doc.contramap[Field](_.prop.doc) ++ - constant("public") ~ constant(sc.name) ~ constant("with") + fieldName.map( - _.capitalize - ) + constant("(") + fieldType ~ fieldName + constant(") {") ++ - constant("return new").map(_.indent(2)) ~ constant(sc.name) + constant( - "(" - ) + PartConv.ofPart(fieldNameList.toPart(sc.fields)) + constant(");") ++ - constant("}").map(_.newline) - - forList(withMethod, _ ++ _).map(_.indent(2).newline).toPart(sc.fields) - } - - val hashcode: PartConv[SourceFile] = - constant[SourceFile]("@Override") ++ constant("public int hashCode() {") ++ - constant("return Objects.hash(").map(_.indent(2)) + fieldNameList - .contramap[SourceFile](_.fields) + constant(");") ++ - constant("}") - - def equals: PartConv[SourceFile] = { - val header: PartConv[SourceFile] = - constant[SourceFile]("@Override") ++ constant( - "public boolean equals(Object other) {" - ) ++ - constant("if (other == this) {").map(_.indent(2)) ++ - constant("return true;").map(_.indent(4)) ++ - constant("}").map(_.indent(2)) ++ - constant("if (other == null || getClass() != other.getClass()) {").map( - _.indent(2) - ) ++ - constant("return false;").map(_.indent(4)) ++ - constant("}").map(_.indent(2)) - - val eq: PartConv[Field] = - constant("Objects.equals(") + fieldName + constant(", v.") + fieldName + constant( - ")" - ) - - (header ++ sourceName.map(_.indent(2)) ~ constant("v = (") + sourceName + constant( - ") other;" - ) ++ - constant("return").map(_.indent(2)) ~ forListSep(eq, Part(" && ")).contramap( - _.fields - ) + constant(";") ++ - constant("}")).map(_.indent(2)) - } - - def tostring: PartConv[SourceFile] = { - val pc: PartConv[SourceFile] = - forListSep(fieldName + constant("=%s"), Part(", ")).contramap(_.fields) - - constant[SourceFile]("@Override") ++ - constant("public String toString() {") ++ - constant("return String.format(\"").map(_.indent(2)) + sourceName + constant( - "[" - ) + pc + constant("]\", ") ++ - fieldNameList.map(_.indent(4)).contramap(_.fields) + constant(");") ++ constant( - "}" - ) - } - - def typeNameList: PartConv[List[Field]] = { - val pc: PartConv[Field] = PartConv { f => - fieldType.toPart(f) ~ Part(f.prop.name) - } - forListSep(pc, Part(", ")) - } - def fieldNameList: PartConv[List[Field]] = { - val pc: PartConv[Field] = PartConv(f => Part(f.prop.name)) - forListSep(pc, Part(", ")) - } - def fieldAssignList: PartConv[List[Field]] = { - val pc: PartConv[Field] = PartConv(f => - Part("this.") + Part(f.prop.name) ~ Part("=") ~ Part(f.prop.name).semicolon - ) - forList(pc, (a, b) => a ++ b) - } - } - - def fileHeader: PartConv[SourceFile] = - pkg.contramap[SourceFile](_.pkg).map(_.semicolon.newline) ++ - imports.contramap[SourceFile](_.imports).map(_.semicolon.newline) ++ - constant("// This is a generated file. Do not edit.").map(_.newline) ++ - doc.contramap(_.doc) - - def generate(sc: SchemaClass, pkg: Pkg, cfg: JavaConfig): (String, String) = { - val tm = defaultTypeMapping(cfg.mapping) - val src = resolveSource(resolveSchema(sc, cfg.mapping), cfg).copy(pkg = pkg) - val conv = fileHeader ++ DataClass(tm, cfg) - (src.name, conv.toPart(src).render) - } - - def resolveSource(src: SourceFile, cfg: JavaConfig): SourceFile = - src - .addImports(Imports.flatten(cfg.builderParents.map(_.imports))) - .addImports(Imports("java.util.Objects", "java.util.Optional")) - .modify(cfg.json.resolve) - - def resolveSchema(sc: SchemaClass, cm: CustomMapping): SourceFile = { - val tm = defaultTypeMapping(cm) - SchemaClass.resolve(sc, Pkg(""), tm, cm) - } -} diff --git a/plugin/src/sbt-test/openapi-test/json-java/build.sbt b/plugin/src/sbt-test/openapi-test/json-java/build.sbt deleted file mode 100644 index d8ce5f7..0000000 --- a/plugin/src/sbt-test/openapi-test/json-java/build.sbt +++ /dev/null @@ -1,18 +0,0 @@ -import com.github.eikek.sbt.openapi._ - -name := "sbt-openapi-simple-test" -version := "0.0.1" -scalaVersion := "2.12.13" - -libraryDependencies ++= Seq( - "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.8", - "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.9.8" -) - -openapiSpec := (Compile/resourceDirectory).value/"test.yml" -openapiTargetLanguage := Language.Java -openapiJavaConfig := JavaConfig.default. - withJson(JavaJson.jackson). - addMapping(CustomMapping.forName({ case s => s + "Dto" })) - -enablePlugins(OpenApiSchema) diff --git a/plugin/src/sbt-test/openapi-test/json-java/project/build.properties b/plugin/src/sbt-test/openapi-test/json-java/project/build.properties deleted file mode 100644 index 67d27a1..0000000 --- a/plugin/src/sbt-test/openapi-test/json-java/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.5.3 diff --git a/plugin/src/sbt-test/openapi-test/json-java/project/plugins.sbt b/plugin/src/sbt-test/openapi-test/json-java/project/plugins.sbt deleted file mode 100644 index 8023524..0000000 --- a/plugin/src/sbt-test/openapi-test/json-java/project/plugins.sbt +++ /dev/null @@ -1,5 +0,0 @@ -sys.props.get("plugin.version") match { - case Some(x) => addSbtPlugin("com.github.eikek" % "sbt-openapi-schema" % x) - case _ => sys.error("""|The system property 'plugin.version' is not defined. - |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) -} diff --git a/plugin/src/sbt-test/openapi-test/json-java/src/main/resources/test.yml b/plugin/src/sbt-test/openapi-test/json-java/src/main/resources/test.yml deleted file mode 100644 index 9d73fc2..0000000 --- a/plugin/src/sbt-test/openapi-test/json-java/src/main/resources/test.yml +++ /dev/null @@ -1,102 +0,0 @@ -openapi: 3.0.0 - -info: - title: Test Simple - version: 0.0.1 - -servers: - - url: /api/v1 - description: Current host - -paths: - -components: - schemas: - Room: - description: | - A room with some properties. - required: - - name - properties: - name: - type: string - seats: - type: integer - format: int32 - - Person: - description: | - A person. - required: - - lastname - properties: - firstname: - description: | - The first name of the person. - type: string - lastname: - description: | - The last name of the person. - type: string - dob: - description: | - The date of birth of a person. - type: string - format: date - - Course: - description: | - A course. - required: - - id - - starts - - room - properties: - id: - description: | - A unique id for this course. - type: string - starts: - description: | - The date when this course starts. - type: string - format: date - room: - $ref: '#/components/schemas/Room' - members: - description: | - A list of members currently enrolled in this course. - type: array - items: - $ref: '#/components/schemas/Person' - - NestedArray: - description: | - Test nested array. - properties: - matrix: - type: array - items: - type: array - items: - type: integer - format: int32 - - SimpleString: - description: - This is just a string. - type: string - - ExtractedData1: - description: | - Contains data from extraction. - type: object - additionalProperties: - $ref: '#/components/schemas/Course' - - ExtractedData2: - description: | - Contains data from extraction. - type: object - additionalProperties: - type: string \ No newline at end of file diff --git a/plugin/src/sbt-test/openapi-test/json-java/src/main/scala/Main.scala b/plugin/src/sbt-test/openapi-test/json-java/src/main/scala/Main.scala deleted file mode 100644 index 9decc1e..0000000 --- a/plugin/src/sbt-test/openapi-test/json-java/src/main/scala/Main.scala +++ /dev/null @@ -1,44 +0,0 @@ -import org.myapi._ -import scala.reflect._ -import com.fasterxml.jackson.databind.ObjectMapper; -import scala.collection.JavaConverters._ -import java.time.LocalDate -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule - -object Main { - private val m = { - val om = new ObjectMapper() - om.registerModule(new JavaTimeModule()) - om - } - - def main(args: Array[String]): Unit = { - List(new RoomDto("main room dto", 68) - , new SimpleStringDto("bla bla bla") - , new ExtractedData1Dto(Map("c1" -> new CourseDto("course10", LocalDate.now, new RoomDto("heat room", 12), List(new PersonDto("hugo", "meyer", null)).asJava)).asJava) - , new ExtractedData2Dto(Map("c1" -> "x1", "c2" -> "x2").asJava) - , new CourseDto("course10", LocalDate.now, new RoomDto("heat room", 12), List(new PersonDto("hugo", "meyer", null)).asJava), - new NestedArrayDto(List(List[Integer](1, 2).asJava, List[Integer](30, 40).asJava).asJava) - ).foreach(testJson _) - - assert(toJson(new SimpleStringDto("bla")) == "\"bla\"") - } - - def testJson(any: Any): Unit = { - println(s"Value: $any") - val clazz = any.getClass - val jsonStr = toJson(any) - println(s"JSON: $jsonStr BACK: ${toValue(jsonStr, clazz)}") - assert(any == toValue(jsonStr, clazz)) - } - - def toJson(any: Any): String = { - m.writeValueAsString(any) - } - - def toValue[A: ClassTag](js: String): A = - toValue(js, classTag[A].runtimeClass.asInstanceOf[Class[A]]) - - def toValue[A](js: String, ct: Class[A]): A = - m.readValue(js, ct) -} diff --git a/plugin/src/sbt-test/openapi-test/json-java/test b/plugin/src/sbt-test/openapi-test/json-java/test deleted file mode 100644 index 237c212..0000000 --- a/plugin/src/sbt-test/openapi-test/json-java/test +++ /dev/null @@ -1,6 +0,0 @@ -# run the task -> openapiCodegen -$ exists target/scala-2.12/src_managed/main/org/myapi/RoomDto.java -# the code should compile -> compile -> run \ No newline at end of file diff --git a/plugin/src/sbt-test/openapi-test/simple-java/build.sbt b/plugin/src/sbt-test/openapi-test/simple-java/build.sbt deleted file mode 100644 index 484fd7b..0000000 --- a/plugin/src/sbt-test/openapi-test/simple-java/build.sbt +++ /dev/null @@ -1,14 +0,0 @@ -import com.github.eikek.sbt.openapi._ - -name := "sbt-openapi-simple-test" -version := "0.0.1" -scalaVersion := "2.12.13" - -enablePlugins(OpenApiSchema) -openapiTargetLanguage := Language.Java -openapiSpec := (Compile/resourceDirectory).value/"test.yml" -openapiJavaConfig := JavaConfig.default. - addMapping(CustomMapping.forType({ - case TypeDef("LocalDate", _) => - TypeDef("Instant", Imports("java.time.Instant")) - })) diff --git a/plugin/src/sbt-test/openapi-test/simple-java/project/plugins.sbt b/plugin/src/sbt-test/openapi-test/simple-java/project/plugins.sbt deleted file mode 100644 index 8023524..0000000 --- a/plugin/src/sbt-test/openapi-test/simple-java/project/plugins.sbt +++ /dev/null @@ -1,5 +0,0 @@ -sys.props.get("plugin.version") match { - case Some(x) => addSbtPlugin("com.github.eikek" % "sbt-openapi-schema" % x) - case _ => sys.error("""|The system property 'plugin.version' is not defined. - |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) -} diff --git a/plugin/src/sbt-test/openapi-test/simple-java/src/main/resources/test.yml b/plugin/src/sbt-test/openapi-test/simple-java/src/main/resources/test.yml deleted file mode 100644 index 9d0e6bf..0000000 --- a/plugin/src/sbt-test/openapi-test/simple-java/src/main/resources/test.yml +++ /dev/null @@ -1,105 +0,0 @@ -openapi: 3.0.0 - -info: - title: Test Simple - version: 0.0.1 - -servers: - - url: /api/v1 - description: Current host - -paths: - -components: - schemas: - Room: - description: | - A room with some properties. - required: - - name - properties: - name: - type: string - seats: - type: integer - format: int32 - roomUri: - description: | - A uri for looking up this room in a cataloge. - type: string - format: uri - - Person: - description: | - A person. - properties: - firstname: - description: | - The first name of the person. - type: string - lastname: - description: | - The last name of the person. - type: string - dob: - description: | - The date of birth of a person. - type: string - format: date - homepage: - description: | - The home page url of that person. - type: string - format: url - - Course: - description: | - A course. - required: - - id - - starts - - room - properties: - id: - description: | - A unique id for this course. - type: string - starts: - description: | - The date when this course starts. - type: string - format: date - room: - $ref: '#/components/schemas/Room' - members: - description: | - A list of members currently enrolled in this course. - type: array - items: - $ref: '#/components/schemas/Person' - - NestedArray: - description: | - Test nested array. - properties: - matrix: - type: array - items: - type: array - items: - type: integer - format: int32 - - ExtractedData1: - description: | - Contains data from extraction. - type: object - additionalProperties: - $ref: '#/components/schemas/Course' - - ExtractedData2: - description: | - Contains data from extraction. - type: object - additionalProperties: - type: string \ No newline at end of file diff --git a/plugin/src/sbt-test/openapi-test/simple-java/src/main/scala/Main.scala b/plugin/src/sbt-test/openapi-test/simple-java/src/main/scala/Main.scala deleted file mode 100644 index e9b239d..0000000 --- a/plugin/src/sbt-test/openapi-test/simple-java/src/main/scala/Main.scala +++ /dev/null @@ -1,14 +0,0 @@ -import org.myapi._ -import java.net.URI -import java.net.URL -import java.util.Optional -import java.time._ - -object Main { - - def main(args: Array[String]): Unit = { - val room = new Room("main room", 68, URI.create("test:a:b")).withName("main room 2") - val person = new Person("Hans", null, Instant.now, new URL("http://test.com")) - println(s"room = $room, person = $person") - } -} diff --git a/plugin/src/sbt-test/openapi-test/simple-java/test b/plugin/src/sbt-test/openapi-test/simple-java/test deleted file mode 100644 index 12cb806..0000000 --- a/plugin/src/sbt-test/openapi-test/simple-java/test +++ /dev/null @@ -1,6 +0,0 @@ -# run the task -> openapiCodegen -$ exists target/scala-2.12/src_managed/main/org/myapi/Room.java -# the code should compile -> compile -> run \ No newline at end of file diff --git a/plugin/src/test/scala/com/github/eikek/sbt/openapi/CodegenSpec.scala b/plugin/src/test/scala/com/github/eikek/sbt/openapi/CodegenSpec.scala index 9a20119..cc952f5 100644 --- a/plugin/src/test/scala/com/github/eikek/sbt/openapi/CodegenSpec.scala +++ b/plugin/src/test/scala/com/github/eikek/sbt/openapi/CodegenSpec.scala @@ -22,34 +22,6 @@ object CodegenSpec extends SimpleTestSuite { } } - test("Running java") { - val typeMapping: CustomMapping = - CustomMapping.forType { - case TypeDef(s, _) if s.startsWith("List<") => - TypeDef( - s.replaceFirst("List", "PList"), - Imports("ch.bluecare.commons.data.PList") - ) - } - - val config = JavaConfig.default - .withJson(JavaJson.jackson) - .addMapping(typeMapping) - .addMapping(CustomMapping.forSource({ case s => s.copy(name = s.name + "Dto") })) - .addMapping(CustomMapping.forSource({ case s => - s.addParents(Superclass("MyFunnyClass", Imports("org.myapp.MyFunnyclass"), false)) - })) - .addBuilderParent( - Superclass("MyBuilderHelper", Imports("org.mylib.BuilderHelper"), true) - ) - - println("=========") - schema.values.foreach { sc => - println("-------------------------------------------------") - println(JavaCode.generate(sc, Pkg("com.test"), config)._2) - } - } - test("Running elm") { val config = ElmConfig.default .addMapping(CustomMapping.forName({ case name => name + "Dto" }))