From 4f98b30bdd83470e099ba4b816bd53566d82c152 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 7 Aug 2018 12:12:27 +0100 Subject: [PATCH 01/39] Kotlin Spring initial bootstrap --- bin/kotlin-spring-server-petstore.sh | 31 +++++++++++++ bin/windows/kotlin-spring-server-petstore.bat | 10 +++++ .../languages/KotlinSpringServerCodegen.java | 45 +++++++++++++++++++ .../org.openapitools.codegen.CodegenConfig | 2 + .../resources/kotlin-spring-server/README.md | 0 .../kotlin-spring-server/api.mustache | 0 .../kotlin-spring-server/model.mustache | 0 .../KotlinSpringServerCodegenModelTest.java | 29 ++++++++++++ .../KotlinSpringServerCodegenOptionsTest.java | 34 ++++++++++++++ .../KotlinSpringServerCodegenTest.java | 19 ++++++++ ...linSpringServerCodegenOptionsProvider.java | 31 +++++++++++++ 11 files changed, 201 insertions(+) create mode 100644 bin/kotlin-spring-server-petstore.sh create mode 100644 bin/windows/kotlin-spring-server-petstore.bat create mode 100644 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring-server/README.md create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring-server/api.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring-server/model.mustache create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java diff --git a/bin/kotlin-spring-server-petstore.sh b/bin/kotlin-spring-server-petstore.sh new file mode 100644 index 000000000000..7fd1703cd45b --- /dev/null +++ b/bin/kotlin-spring-server-petstore.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=$(ls -ld "$SCRIPT") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=$(dirname "$SCRIPT")/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=$(dirname "$SCRIPT")/.. + APP_DIR=$(cd "${APP_DIR}"; pwd) +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g kotlin-spring -o samples/server/petstore/kotlin-spring" + +java ${JAVA_OPTS} -jar ${executable} ${ags} diff --git a/bin/windows/kotlin-spring-server-petstore.bat b/bin/windows/kotlin-spring-server-petstore.bat new file mode 100644 index 000000000000..3036b2f56be1 --- /dev/null +++ b/bin/windows/kotlin-spring-server-petstore.bat @@ -0,0 +1,10 @@ +set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties +set ags=generate --artifact-id "kotlin-spring-petstore-server" -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g kotlin-spring -o samples\server\petstore\kotlin-spring + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java new file mode 100644 index 000000000000..900bd26893a6 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -0,0 +1,45 @@ +package org.openapitools.codegen.languages; + +import org.openapitools.codegen.*; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.parameters.Parameter; + +import java.io.File; +import java.util.*; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KotlinSpringServerCodegen extends DefaultCodegen implements CodegenConfig { + public static final String PROJECT_NAME = "projectName"; + + static Logger LOGGER = LoggerFactory.getLogger(KotlinSpringServerCodegen.class); + + public CodegenType getTag() { + return CodegenType.SERVER; + } + + public String getName() { + return "kotlin-spring"; + } + + public String getHelp() { + return "Generates a kotlin-spring server."; + } + + public KotlinSpringServerCodegen() { + super(); + + outputFolder = "generated-code" + File.separator + "kotlin-spring"; + modelTemplateFiles.put("model.mustache", ".zz"); + apiTemplateFiles.put("api.mustache", ".zz"); + embeddedTemplateDir = templateDir = "kotlin-spring"; + apiPackage = File.separator + "Apis"; + modelPackage = File.separator + "Models"; + // TODO: Fill this out. + } +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index a5c3d07b08a6..14ded6d7b414 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -91,3 +91,5 @@ org.openapitools.codegen.languages.TypeScriptFetchClientCodegen org.openapitools.codegen.languages.TypeScriptInversifyClientCodegen org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen org.openapitools.codegen.languages.TypeScriptNodeClientCodegen + +org.openapitools.codegen.languages.KotlinSpringServerCodegen diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring-server/README.md b/modules/openapi-generator/src/main/resources/kotlin-spring-server/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring-server/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring-server/api.mustache new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring-server/model.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring-server/model.mustache new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java new file mode 100644 index 000000000000..876466792312 --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java @@ -0,0 +1,29 @@ +package org.openapitools.codegen.kotlin-spring; + +import org.openapitools.codegen.*; +import org.openapitools.codegen.languages.KotlinSpringServerCodegen; +import io.swagger.models.*; +import io.swagger.models.properties.*; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@SuppressWarnings("static-method") +public class KotlinSpringServerCodegenModelTest { + + @Test(description = "convert a simple java model") + public void simpleModelTest() { + final Model model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("name", new StringProperty()) + .required("id") + .required("name"); + final DefaultCodegen codegen = new KotlinSpringServerCodegen(); + + // TODO: Complete this test. + Assert.fail("Not implemented."); + } + +} + diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java new file mode 100644 index 000000000000..4986aa699b5a --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java @@ -0,0 +1,34 @@ +package org.openapitools.codegen.kotlin-spring; + +import org.openapitools.codegen.AbstractOptionsTest; +import org.openapitools.codegen.CodegenConfig; +import org.openapitools.codegen.languages.KotlinSpringServerCodegen; +import org.openapitools.codegen.options.KotlinSpringServerCodegenOptionsProvider; + +import mockit.Expectations; +import mockit.Tested; + +public class KotlinSpringServerCodegenOptionsTest extends AbstractOptionsTest { + + @Tested + private KotlinSpringServerCodegen codegen; + + public KotlinSpringServerCodegenOptionsTest() { + super(new KotlinSpringServerCodegenOptionsProvider()); + } + + @Override + protected CodegenConfig getCodegenConfig() { + return codegen; + } + + @SuppressWarnings("unused") + @Override + protected void setExpectations() { + // TODO: Complete options + new Expectations(codegen) {{ + + }}; + } +} + diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java new file mode 100644 index 000000000000..03f9e257f3c2 --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java @@ -0,0 +1,19 @@ +package org.openapitools.codegen.kotlin-spring; + +import org.openapitools.codegen.*; +import org.openapitools.codegen.languages.KotlinSpringServerCodegen; +import io.swagger.models.*; +import io.swagger.parser.SwaggerParser; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class KotlinSpringServerCodegenTest { + + KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen(); + + @Test + public void shouldSucceed() throws Exception { + // TODO: Complete this test. + Assert.fail("Not implemented."); + } +} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java new file mode 100644 index 000000000000..5961327418ce --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java @@ -0,0 +1,31 @@ +package org.openapitools.codegen.options; + +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.languages.KotlinSpringServerCodegen; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +public class KotlinSpringServerCodegenOptionsProvider implements OptionsProvider { + public static final String PROJECT_NAME_VALUE = "OpenAPI"; + + @Override + public String getLanguage() { + return "kotlin-spring"; + } + + @Override + public Map createOptions() { + ImmutableMap.Builder builder = new ImmutableMap.Builder(); + return builder + .put(KotlinSpringServerCodegen.PROJECT_NAME, PROJECT_NAME_VALUE) + .build(); + } + + @Override + public boolean isServer() { + return false; + } +} + From b2be108932d343dd833ed86b2233d980432cf0eb Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 7 Aug 2018 17:45:05 +0100 Subject: [PATCH 02/39] Basic configuration construction for Kotlin Spring --- bin/kotlin-spring-server-petstore.sh | 0 .../languages/KotlinSpringServerCodegen.java | 159 ++++++++++++++++-- .../KotlinSpringServerCodegenModelTest.java | 29 ---- .../KotlinSpringServerCodegenOptionsTest.java | 34 ---- .../KotlinSpringServerCodegenTest.java | 19 --- .../spring/KotlinSpringServerCodegenTest.java | 84 +++++++++ 6 files changed, 225 insertions(+), 100 deletions(-) mode change 100644 => 100755 bin/kotlin-spring-server-petstore.sh delete mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java delete mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java delete mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java diff --git a/bin/kotlin-spring-server-petstore.sh b/bin/kotlin-spring-server-petstore.sh old mode 100644 new mode 100755 diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 900bd26893a6..e6b2c41bd9b8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -1,24 +1,32 @@ package org.openapitools.codegen.languages; -import org.openapitools.codegen.*; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.parameters.Parameter; - -import java.io.File; -import java.util.*; - -import org.apache.commons.lang3.StringUtils; - +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class KotlinSpringServerCodegen extends DefaultCodegen implements CodegenConfig { +import java.net.URL; +import java.util.*; + +public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { public static final String PROJECT_NAME = "projectName"; static Logger LOGGER = LoggerFactory.getLogger(KotlinSpringServerCodegen.class); + // TODO handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" + public static final String TITLE = "title"; + public static final String SERVER_PORT = "serverPort"; + public static final String BASE_PACKAGE = "basePackage"; + public static final String CONFIG_PACKAGE = "configPackage"; + + protected String basePackage; + protected String configPackage; + protected String serverPort = "8082"; + protected String title = "OpenAPI Kotlin Spring"; + public CodegenType getTag() { return CodegenType.SERVER; } @@ -34,12 +42,127 @@ public String getHelp() { public KotlinSpringServerCodegen() { super(); - outputFolder = "generated-code" + File.separator + "kotlin-spring"; - modelTemplateFiles.put("model.mustache", ".zz"); - apiTemplateFiles.put("api.mustache", ".zz"); + outputFolder = "generated-code/kotlin-spring"; + apiTestTemplateFiles.clear(); // TODO: add test template embeddedTemplateDir = templateDir = "kotlin-spring"; - apiPackage = File.separator + "Apis"; - modelPackage = File.separator + "Models"; - // TODO: Fill this out. + + artifactId = "openapi-spring"; + basePackage = "org.openapitools"; + apiPackage = "org.openapitools.api"; + modelPackage = "org.openapitools.model"; + configPackage = "org.openapitools.conf"; + + // spring uses the jackson lib + additionalProperties.put("jackson", "true"); + +// modelTemplateFiles.put("model.mustache", ".zz"); +// apiTemplateFiles.put("api.mustache", ".zz"); } + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey(BASE_PACKAGE)) { + this.setBasePackage((String) additionalProperties.get(BASE_PACKAGE)); + } else { + additionalProperties.put(BASE_PACKAGE, basePackage); + } + + if (additionalProperties.containsKey(SERVER_PORT)) { + this.setServerPort((String) additionalProperties.get(SERVER_PORT)); + } else { + additionalProperties.put(SERVER_PORT, serverPort); + } + + if (additionalProperties.containsKey(CONFIG_PACKAGE)) { + this.setConfigPackage((String) additionalProperties.get(CONFIG_PACKAGE)); + } else { + additionalProperties.put(CONFIG_PACKAGE, configPackage); + } + } + + public String getBasePackage() { + return this.basePackage; + } + + public void setBasePackage(String basePackage) { + this.basePackage = basePackage; + } + + public String getConfigPackage() { + return this.configPackage; + } + + public void setConfigPackage(String configPackage) { + this.configPackage = configPackage; + } + + public String getServerPort() { + return this.serverPort; + } + + public void setServerPort(String serverPort) { + this.serverPort = serverPort; + } + + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + /* TODO the following logic should not need anymore in OAS 3.0 + if ("/".equals(swagger.getBasePath())) { + swagger.setBasePath(""); + } + */ + + if (!additionalProperties.containsKey(TITLE)) { + // From the title, compute a reasonable name for the package and the API + String title = openAPI.getInfo().getTitle(); + + // Drop any API suffix + if (title != null) { + title = title.trim().replace(" ", "-"); + if (title.toUpperCase().endsWith("API")) { + title = title.substring(0, title.length() - 3); + } + + this.title = camelize(sanitizeName(title), true); + } + additionalProperties.put(TITLE, this.title); + } + + if (!additionalProperties.containsKey(SERVER_PORT)) { + URL url = URLPathUtils.getServerURL(openAPI); + this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080)); + } + + if (openAPI.getPaths() != null) { + for (String pathname : openAPI.getPaths().keySet()) { + PathItem path = openAPI.getPaths().get(pathname); + if (path.readOperations() != null) { + for (Operation operation : path.readOperations()) { + if (operation.getTags() != null) { + List> tags = new ArrayList>(); + for (String tag : operation.getTags()) { + Map value = new HashMap(); + value.put("tag", tag); + value.put("hasMore", "true"); + tags.add(value); + } + if (tags.size() > 0) { + tags.get(tags.size() - 1).remove("hasMore"); + } + if (operation.getTags().size() > 0) { + String tag = operation.getTags().get(0); + operation.setTags(Arrays.asList(tag)); + } + operation.addExtension("x-tags", tags); + } + } + } + } + } + } + + } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java deleted file mode 100644 index 876466792312..000000000000 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenModelTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.openapitools.codegen.kotlin-spring; - -import org.openapitools.codegen.*; -import org.openapitools.codegen.languages.KotlinSpringServerCodegen; -import io.swagger.models.*; -import io.swagger.models.properties.*; - -import org.testng.Assert; -import org.testng.annotations.Test; - -@SuppressWarnings("static-method") -public class KotlinSpringServerCodegenModelTest { - - @Test(description = "convert a simple java model") - public void simpleModelTest() { - final Model model = new ModelImpl() - .description("a sample model") - .property("id", new LongProperty()) - .property("name", new StringProperty()) - .required("id") - .required("name"); - final DefaultCodegen codegen = new KotlinSpringServerCodegen(); - - // TODO: Complete this test. - Assert.fail("Not implemented."); - } - -} - diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java deleted file mode 100644 index 4986aa699b5a..000000000000 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenOptionsTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.openapitools.codegen.kotlin-spring; - -import org.openapitools.codegen.AbstractOptionsTest; -import org.openapitools.codegen.CodegenConfig; -import org.openapitools.codegen.languages.KotlinSpringServerCodegen; -import org.openapitools.codegen.options.KotlinSpringServerCodegenOptionsProvider; - -import mockit.Expectations; -import mockit.Tested; - -public class KotlinSpringServerCodegenOptionsTest extends AbstractOptionsTest { - - @Tested - private KotlinSpringServerCodegen codegen; - - public KotlinSpringServerCodegenOptionsTest() { - super(new KotlinSpringServerCodegenOptionsProvider()); - } - - @Override - protected CodegenConfig getCodegenConfig() { - return codegen; - } - - @SuppressWarnings("unused") - @Override - protected void setExpectations() { - // TODO: Complete options - new Expectations(codegen) {{ - - }}; - } -} - diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java deleted file mode 100644 index 03f9e257f3c2..000000000000 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin-spring/KotlinSpringServerCodegenTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.openapitools.codegen.kotlin-spring; - -import org.openapitools.codegen.*; -import org.openapitools.codegen.languages.KotlinSpringServerCodegen; -import io.swagger.models.*; -import io.swagger.parser.SwaggerParser; -import org.testng.Assert; -import org.testng.annotations.Test; - -public class KotlinSpringServerCodegenTest { - - KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen(); - - @Test - public void shouldSucceed() throws Exception { - // TODO: Complete this test. - Assert.fail("Not implemented."); - } -} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java new file mode 100644 index 000000000000..5f50e1702e8c --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -0,0 +1,84 @@ +package org.openapitools.codegen.kotlin.spring; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.servers.Server; +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.languages.KotlinSpringServerCodegen; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class KotlinSpringServerCodegenTest { + + @Test + public void testInitialConfigValues() throws Exception { + final KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen(); + codegen.processOpts(); + + OpenAPI openAPI = new OpenAPI(); + openAPI.addServersItem(new Server().url("https://api.abcde.xy:8082/v2")); + openAPI.setInfo(new Info()); + codegen.preprocessOpenAPI(openAPI); + + Assert.assertEquals(codegen.modelPackage(), "org.openapitools.model"); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.MODEL_PACKAGE), "org.openapitools.model"); + Assert.assertEquals(codegen.apiPackage(), "org.openapitools.api"); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "org.openapitools.api"); + Assert.assertEquals(codegen.getBasePackage(), "org.openapitools"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "org.openapitools"); + Assert.assertEquals(codegen.getConfigPackage(), "org.openapitools.conf"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.CONFIG_PACKAGE), "org.openapitools.conf"); + Assert.assertEquals(codegen.getServerPort(), "8082"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8082"); + } + + @Test + public void testSettersForConfigValues() throws Exception { + final KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen(); + codegen.setModelPackage("xx.yyyyyyyy.model"); + codegen.setApiPackage("xx.yyyyyyyy.api"); + codegen.setBasePackage("xx.yyyyyyyy.base"); + codegen.setConfigPackage("xx.yyyyyyyy.config"); + codegen.setServerPort("8181"); + codegen.processOpts(); + + Assert.assertEquals(codegen.modelPackage(), "xx.yyyyyyyy.model"); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.MODEL_PACKAGE), "xx.yyyyyyyy.model"); + Assert.assertEquals(codegen.apiPackage(), "xx.yyyyyyyy.api"); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "xx.yyyyyyyy.api"); + Assert.assertEquals(codegen.getBasePackage(), "xx.yyyyyyyy.base"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "xx.yyyyyyyy.base"); + Assert.assertEquals(codegen.getConfigPackage(), "xx.yyyyyyyy.config"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.CONFIG_PACKAGE), "xx.yyyyyyyy.config"); + Assert.assertEquals(codegen.getServerPort(), "8181"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8181"); + } + + @Test + public void testAdditionalPropertiesPutForConfigValues() throws Exception { + final KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen(); + codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "xyz.yyyyy.mmmmm.model"); + codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "xyz.yyyyy.aaaaa.api"); + codegen.additionalProperties().put(KotlinSpringServerCodegen.BASE_PACKAGE, "xyz.yyyyy.bbbb.base"); + codegen.additionalProperties().put(KotlinSpringServerCodegen.CONFIG_PACKAGE, "xyz.yyyyy.cccc.config"); + codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVER_PORT, "8088"); + codegen.processOpts(); + + OpenAPI openAPI = new OpenAPI(); + openAPI.addServersItem(new Server().url("https://api.abcde.xy:8082/v2")); + openAPI.setInfo(new Info()); + openAPI.getInfo().setTitle("Some test API"); + codegen.preprocessOpenAPI(openAPI); + + Assert.assertEquals(codegen.modelPackage(), "xyz.yyyyy.mmmmm.model"); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.MODEL_PACKAGE), "xyz.yyyyy.mmmmm.model"); + Assert.assertEquals(codegen.apiPackage(), "xyz.yyyyy.aaaaa.api"); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "xyz.yyyyy.aaaaa.api"); + Assert.assertEquals(codegen.getBasePackage(), "xyz.yyyyy.bbbb.base"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "xyz.yyyyy.bbbb.base"); + Assert.assertEquals(codegen.getConfigPackage(), "xyz.yyyyy.cccc.config"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.CONFIG_PACKAGE), "xyz.yyyyy.cccc.config"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.TITLE), "someTest"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8088"); + } +} From 3013f09b70d5a6559f0781b17b0b9043b5ebb65b Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 8 Aug 2018 13:45:47 +0100 Subject: [PATCH 03/39] Wired up with comand line client --- .../languages/KotlinSpringServerCodegen.java | 57 +++++++++++++------ .../org.openapitools.codegen.CodegenConfig | 1 - .../README.md | 0 .../api.mustache | 0 .../libraries/spring-boot/pom.mustache | 8 +++ .../model.mustache | 0 ...linSpringServerCodegenOptionsProvider.java | 31 ---------- 7 files changed, 49 insertions(+), 48 deletions(-) rename modules/openapi-generator/src/main/resources/{kotlin-spring-server => kotlin-spring}/README.md (100%) rename modules/openapi-generator/src/main/resources/{kotlin-spring-server => kotlin-spring}/api.mustache (100%) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache rename modules/openapi-generator/src/main/resources/{kotlin-spring-server => kotlin-spring}/model.mustache (100%) delete mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index e6b2c41bd9b8..3a6521cf008e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -3,7 +3,10 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; +import org.openapitools.codegen.CliOption; +import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.SupportingFile; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,33 +15,22 @@ import java.util.*; public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { - public static final String PROJECT_NAME = "projectName"; - static Logger LOGGER = LoggerFactory.getLogger(KotlinSpringServerCodegen.class); + private static Logger LOGGER = + LoggerFactory.getLogger(KotlinSpringServerCodegen.class); // TODO handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" public static final String TITLE = "title"; public static final String SERVER_PORT = "serverPort"; public static final String BASE_PACKAGE = "basePackage"; public static final String CONFIG_PACKAGE = "configPackage"; + public static final String SPRING_BOOT = "spring-boot"; protected String basePackage; protected String configPackage; protected String serverPort = "8082"; protected String title = "OpenAPI Kotlin Spring"; - public CodegenType getTag() { - return CodegenType.SERVER; - } - - public String getName() { - return "kotlin-spring"; - } - - public String getHelp() { - return "Generates a kotlin-spring server."; - } - public KotlinSpringServerCodegen() { super(); @@ -55,14 +47,49 @@ public KotlinSpringServerCodegen() { // spring uses the jackson lib additionalProperties.put("jackson", "true"); + addOption(TITLE, "server title name or client service name", title); + addOption(BASE_PACKAGE, "base package for generated code", basePackage); + addOption(CONFIG_PACKAGE, "configuration package for generated code", configPackage); + addOption(CodegenConstants.MODEL_PACKAGE, "model package for generated code", modelPackage); + addOption(CodegenConstants.API_PACKAGE, "api package for generated code", apiPackage); + + supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application using the SpringFox integration."); + setLibrary(SPRING_BOOT); + + CliOption library = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); + library.setDefault(SPRING_BOOT); + library.setEnum(supportedLibraries); + cliOptions.add(library); + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + // modelTemplateFiles.put("model.mustache", ".zz"); // apiTemplateFiles.put("api.mustache", ".zz"); } + @Override + public CodegenType getTag() { + return CodegenType.SERVER; + } + + @Override + public String getName() { + return "kotlin-spring"; + } + + @Override + public String getHelp() { + return "Generates a Kotlin Spring application using the SpringFox integration."; + } + @Override public void processOpts() { super.processOpts(); + if (!additionalProperties.containsKey(CodegenConstants.LIBRARY)) { + additionalProperties.put(CodegenConstants.LIBRARY, library); + } + if (additionalProperties.containsKey(BASE_PACKAGE)) { this.setBasePackage((String) additionalProperties.get(BASE_PACKAGE)); } else { @@ -163,6 +190,4 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } } - - } diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 14ded6d7b414..5e27cd01c56c 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -91,5 +91,4 @@ org.openapitools.codegen.languages.TypeScriptFetchClientCodegen org.openapitools.codegen.languages.TypeScriptInversifyClientCodegen org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen org.openapitools.codegen.languages.TypeScriptNodeClientCodegen - org.openapitools.codegen.languages.KotlinSpringServerCodegen diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring-server/README.md b/modules/openapi-generator/src/main/resources/kotlin-spring/README.md similarity index 100% rename from modules/openapi-generator/src/main/resources/kotlin-spring-server/README.md rename to modules/openapi-generator/src/main/resources/kotlin-spring/README.md diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring-server/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache similarity index 100% rename from modules/openapi-generator/src/main/resources/kotlin-spring-server/api.mustache rename to modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache new file mode 100644 index 000000000000..d00bcbfb2635 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache @@ -0,0 +1,8 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring-server/model.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache similarity index 100% rename from modules/openapi-generator/src/main/resources/kotlin-spring-server/model.mustache rename to modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java deleted file mode 100644 index 5961327418ce..000000000000 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinSpringServerCodegenOptionsProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.openapitools.codegen.options; - -import org.openapitools.codegen.CodegenConstants; -import org.openapitools.codegen.languages.KotlinSpringServerCodegen; - -import com.google.common.collect.ImmutableMap; - -import java.util.Map; - -public class KotlinSpringServerCodegenOptionsProvider implements OptionsProvider { - public static final String PROJECT_NAME_VALUE = "OpenAPI"; - - @Override - public String getLanguage() { - return "kotlin-spring"; - } - - @Override - public Map createOptions() { - ImmutableMap.Builder builder = new ImmutableMap.Builder(); - return builder - .put(KotlinSpringServerCodegen.PROJECT_NAME, PROJECT_NAME_VALUE) - .build(); - } - - @Override - public boolean isServer() { - return false; - } -} - From 2644e0df7a104de0ddc43ee9c9a7db9d74322ea4 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 8 Aug 2018 16:35:56 +0100 Subject: [PATCH 04/39] Initial kotlin spring boot application generated using gradle kotlin-dsl --- .../languages/KotlinSpringServerCodegen.java | 38 ++++++++++++----- .../spring-boot/application.mustache | 3 ++ .../spring-boot/buildGradleKts.mustache | 42 +++++++++++++++++++ .../spring-boot/openapi2SpringBoot.mustache | 12 ++++++ .../libraries/spring-boot/pom.mustache | 8 ---- .../spring-boot/settingsGradle.mustache | 1 + .../spring/KotlinSpringServerCodegenTest.java | 4 +- 7 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/application.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache delete mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/settingsGradle.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 3a6521cf008e..d9706eb7d0a2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -11,24 +11,30 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; import java.net.URL; import java.util.*; +/** + * TODO handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" + * TODO integrate Spring Fox + */ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { private static Logger LOGGER = LoggerFactory.getLogger(KotlinSpringServerCodegen.class); - // TODO handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" public static final String TITLE = "title"; public static final String SERVER_PORT = "serverPort"; public static final String BASE_PACKAGE = "basePackage"; public static final String CONFIG_PACKAGE = "configPackage"; public static final String SPRING_BOOT = "spring-boot"; + protected String resourceFolder = "src/main/resources"; + protected String basePackage; protected String configPackage; - protected String serverPort = "8082"; + protected String serverPort = "8080"; protected String title = "OpenAPI Kotlin Spring"; public KotlinSpringServerCodegen() { @@ -50,18 +56,17 @@ public KotlinSpringServerCodegen() { addOption(TITLE, "server title name or client service name", title); addOption(BASE_PACKAGE, "base package for generated code", basePackage); addOption(CONFIG_PACKAGE, "configuration package for generated code", configPackage); + addOption(SERVER_PORT, "configuration the port in which the sever is to run on", serverPort); addOption(CodegenConstants.MODEL_PACKAGE, "model package for generated code", modelPackage); addOption(CodegenConstants.API_PACKAGE, "api package for generated code", apiPackage); - supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application using the SpringFox integration."); + supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); setLibrary(SPRING_BOOT); - CliOption library = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); - library.setDefault(SPRING_BOOT); - library.setEnum(supportedLibraries); - cliOptions.add(library); - - supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + CliOption cliOpt = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); + cliOpt.setDefault(SPRING_BOOT); + cliOpt.setEnum(supportedLibraries); + cliOptions.add(cliOpt); // modelTemplateFiles.put("model.mustache", ".zz"); // apiTemplateFiles.put("api.mustache", ".zz"); @@ -79,7 +84,7 @@ public String getName() { @Override public String getHelp() { - return "Generates a Kotlin Spring application using the SpringFox integration."; + return "Generates a Kotlin Spring application."; } @Override @@ -107,6 +112,15 @@ public void processOpts() { } else { additionalProperties.put(CONFIG_PACKAGE, configPackage); } + + supportingFiles.add(new SupportingFile("buildGradleKts.mustache", "", "build.gradle.kts")); + supportingFiles.add(new SupportingFile("settingsGradle.mustache", "", "settings.gradle")); + supportingFiles.add(new SupportingFile("application.mustache", resourceFolder, "application.yaml")); + + if (library.equals(SPRING_BOOT)) { + supportingFiles.add(new SupportingFile("openapi2SpringBoot.mustache", + sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); + } } public String getBasePackage() { @@ -190,4 +204,8 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } } + + private static String sanitizeDirectory(String in) { + return in.replace(".", File.separator); + } } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/application.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/application.mustache new file mode 100644 index 000000000000..b3245b774810 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/application.mustache @@ -0,0 +1,3 @@ +spring.application.name={{title}} +server.port={{serverPort}} +spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache new file mode 100644 index 000000000000..fd900dcf7d66 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache @@ -0,0 +1,42 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +buildscript { + repositories { + jcenter() + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE") + } +} + +group = "{{groupId}}" +version = "{{artifactVersion}}" + +repositories { + jcenter() + mavenCentral() +} + +tasks.withType { + kotlinOptions.jvmTarget = "1.8" +} + +plugins { + val kotlinVersion = "1.2.41" + id("org.jetbrains.kotlin.jvm") version kotlinVersion + id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion + id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion + id("org.springframework.boot") version "2.0.3.RELEASE" + id("io.spring.dependency-management") version "1.0.5.RELEASE" +} + +dependencies { + compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + compile("org.jetbrains.kotlin:kotlin-reflect") + compile("org.springframework.boot:spring-boot-starter-web") + + testCompile("org.springframework.boot:spring-boot-starter-test") { + exclude(module = "junit") + } +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache new file mode 100644 index 000000000000..0b4f3c62a3be --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache @@ -0,0 +1,12 @@ +package {{basePackage}} + +import org.springframework.boot.runApplication +import org.springframework.boot.autoconfigure.SpringBootApplication + + +@SpringBootApplication +class Application + +fun main(args: Array) { + runApplication(*args) +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache deleted file mode 100644 index d00bcbfb2635..000000000000 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache +++ /dev/null @@ -1,8 +0,0 @@ - - 4.0.0 - {{groupId}} - {{artifactId}} - jar - {{artifactId}} - {{artifactVersion}} - diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/settingsGradle.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/settingsGradle.mustache new file mode 100644 index 000000000000..b8fd6c4c41f9 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/settingsGradle.mustache @@ -0,0 +1 @@ +rootProject.name = "{{artifactId}}" \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index 5f50e1702e8c..9b852821df22 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -28,8 +28,8 @@ public void testInitialConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "org.openapitools"); Assert.assertEquals(codegen.getConfigPackage(), "org.openapitools.conf"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.CONFIG_PACKAGE), "org.openapitools.conf"); - Assert.assertEquals(codegen.getServerPort(), "8082"); - Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8082"); + Assert.assertEquals(codegen.getServerPort(), "8080"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8080"); } @Test From aa001f9f41f59a158ef6a82cd1366781aef1b529 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Thu, 9 Aug 2018 10:21:13 +0100 Subject: [PATCH 05/39] Added basic support for generating models --- .../languages/KotlinSpringServerCodegen.java | 90 +++++++++++++++++-- .../kotlin-spring/dataClass.mustache | 25 ++++++ .../kotlin-spring/dataClassOptVar.mustache | 4 + .../kotlin-spring/dataClassReqVar.mustache | 4 + .../resources/kotlin-spring/model.mustache | 13 +++ .../spring/KotlinSpringServerCodegenTest.java | 4 +- 6 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index d9706eb7d0a2..69f9c911f0cc 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -3,10 +3,7 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; -import org.openapitools.codegen.CliOption; -import org.openapitools.codegen.CodegenConstants; -import org.openapitools.codegen.CodegenType; -import org.openapitools.codegen.SupportingFile; +import org.openapitools.codegen.*; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,8 +13,16 @@ import java.util.*; /** - * TODO handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" - * TODO integrate Spring Fox + * TODO Config: + * - handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" + * - integrate Spring Fox + * TODO Model generation: + * - serializableModel by implementing java.io.Serializable + * - enable optional bean validation using javax.validation.Valid (currently must be valid) + * - support enums in model generation: + * isEnum + * enumOuterClass + * isEnum */ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { @@ -68,7 +73,7 @@ public KotlinSpringServerCodegen() { cliOpt.setEnum(supportedLibraries); cliOptions.add(cliOpt); -// modelTemplateFiles.put("model.mustache", ".zz"); + modelTemplateFiles.put("model.mustache", ".kt"); // apiTemplateFiles.put("api.mustache", ".zz"); } @@ -91,6 +96,32 @@ public String getHelp() { public void processOpts() { super.processOpts(); + // optional jackson mappings for BigDecimal support + importMapping.put("ToStringSerializer", "com.fasterxml.jackson.databind.ser.std.ToStringSerializer"); + importMapping.put("JsonSerialize", "com.fasterxml.jackson.databind.annotation.JsonSerialize"); + + // Java import mappings + importMapping.put("Objects", "java.util.Objects"); + importMapping.put("IOException", "java.io.IOException"); + + // Swagger import mappings + importMapping.put("ApiModel", "io.swagger.annotations.ApiModel"); + importMapping.put("ApiModelProperty", "io.swagger.annotations.ApiModelProperty"); + + // Jackson import mappings + importMapping.put("JsonValue", "com.fasterxml.jackson.annotation.JsonValue"); + importMapping.put("JsonCreator", "com.fasterxml.jackson.annotation.JsonCreator"); + importMapping.put("SerializedName", "com.google.gson.annotations.SerializedName"); + importMapping.put("JsonProperty", "com.fasterxml.jackson.annotation.JsonProperty"); + importMapping.put("JsonSubTypes", "com.fasterxml.jackson.annotation.JsonSubTypes"); + importMapping.put("JsonTypeInfo", "com.fasterxml.jackson.annotation.JsonTypeInfo"); + // import JsonCreator if JsonProperty is imported + // used later in recursive import in postProcessingModels + importMapping.put("com.fasterxml.jackson.annotation.JsonProperty", "com.fasterxml.jackson.annotation.JsonCreator"); + + // TODO when adding invokerPackage + //importMapping.put("StringUtil", invokerPackage + ".StringUtil"); + if (!additionalProperties.containsKey(CodegenConstants.LIBRARY)) { additionalProperties.put(CodegenConstants.LIBRARY, library); } @@ -205,6 +236,51 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } + @Override + public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { + super.postProcessModelProperty(model, property); + + if ("null".equals(property.example)) { + property.example = null; + } + + //Add imports for Jackson + if (!Boolean.TRUE.equals(model.isEnum)) { + model.imports.add("JsonProperty"); + + if (Boolean.TRUE.equals(model.hasEnums)) { + model.imports.add("JsonValue"); + } + } else { // enum class + //Needed imports for Jackson's JsonCreator + if (additionalProperties.containsKey("jackson")) { + model.imports.add("JsonCreator"); + } + } + } + + @Override + public Map postProcessModelsEnum(Map objs) { + objs = super.postProcessModelsEnum(objs); + + //Add imports for Jackson + List> imports = (List>) objs.get("imports"); + List models = (List) objs.get("models"); + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + // for enum model + if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) { + cm.imports.add(importMapping.get("JsonValue")); + Map item = new HashMap(); + item.put("import", importMapping.get("JsonValue")); + imports.add(item); + } + } + + return objs; + } + private static String sanitizeDirectory(String in) { return in.replace(".", File.separator); } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache new file mode 100644 index 000000000000..8a40b23e946c --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache @@ -0,0 +1,25 @@ +/** + * {{{description}}} +{{#vars}} + * @param {{name}} {{{description}}} +{{/vars}} + */ +data class {{classname}} ( +{{#requiredVars}} +{{>dataClassReqVar}}{{^-last}}, +{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}}, +{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>dataClassOptVar}}{{^-last}}, +{{/-last}}{{/optionalVars}} +) { +{{#hasEnums}}{{#vars}}{{#isEnum}} + /** + * {{{description}}} + * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} + */ + enum class {{nameInCamelCase}}(val value: {{dataType}}) { + {{#allowableValues}}{{#enumVars}} + @JsonProperty({{{value}}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} + {{/enumVars}}{{/allowableValues}} + } +{{/isEnum}}{{/vars}}{{/hasEnums}} +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache new file mode 100644 index 000000000000..32f9a32a98db --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache @@ -0,0 +1,4 @@ +{{#description}} + /* {{{description}}} */ +{{/description}} + @JsonProperty("{{{name}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache new file mode 100644 index 000000000000..4aa15c8b05a2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache @@ -0,0 +1,4 @@ +{{#description}} + /* {{{description}}} */ +{{/description}} + @JsonProperty("{{{name}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache index e69de29bb2d1..e6baa088ae95 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache @@ -0,0 +1,13 @@ +package {{package}} + +import java.util.Objects +{{#imports}}import {{import}} +{{/imports}} +import javax.validation.Valid +import javax.validation.constraints.* + +{{#models}} +{{#model}} +{{>dataClass}} +{{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index 9b852821df22..f09acc57aec4 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -15,7 +15,7 @@ public void testInitialConfigValues() throws Exception { final KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen(); codegen.processOpts(); - OpenAPI openAPI = new OpenAPI(); + final OpenAPI openAPI = new OpenAPI(); openAPI.addServersItem(new Server().url("https://api.abcde.xy:8082/v2")); openAPI.setInfo(new Info()); codegen.preprocessOpenAPI(openAPI); @@ -64,7 +64,7 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVER_PORT, "8088"); codegen.processOpts(); - OpenAPI openAPI = new OpenAPI(); + final OpenAPI openAPI = new OpenAPI(); openAPI.addServersItem(new Server().url("https://api.abcde.xy:8082/v2")); openAPI.setInfo(new Info()); openAPI.getInfo().setTitle("Some test API"); From cfca803a53a3eebf97223c2d1c925d8398df13e6 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Thu, 9 Aug 2018 14:51:37 +0100 Subject: [PATCH 06/39] Basic controllers generated without endpoints generated --- .../languages/KotlinSpringServerCodegen.java | 86 +++++++++---------- .../kotlin-spring/apiController.mustache | 31 +++++++ .../spring-boot/buildGradleKts.mustache | 1 + .../spring-boot/defaultBasePath.mustache | 1 + .../spring-boot/openapi2SpringBoot.mustache | 2 + 5 files changed, 75 insertions(+), 46 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 69f9c911f0cc..14def5a94ab6 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -1,8 +1,6 @@ package org.openapitools.codegen.languages; import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.PathItem; import org.openapitools.codegen.*; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; @@ -151,6 +149,7 @@ public void processOpts() { if (library.equals(SPRING_BOOT)) { supportingFiles.add(new SupportingFile("openapi2SpringBoot.mustache", sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); + apiTemplateFiles.put("apiController.mustache", "Controller.kt"); } } @@ -194,9 +193,8 @@ public void preprocessOpenAPI(OpenAPI openAPI) { // Drop any API suffix if (title != null) { title = title.trim().replace(" ", "-"); - if (title.toUpperCase().endsWith("API")) { + if (title.toUpperCase().endsWith("API")) title = title.substring(0, title.length() - 3); - } this.title = camelize(sanitizeName(title), true); } @@ -209,30 +207,29 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } if (openAPI.getPaths() != null) { - for (String pathname : openAPI.getPaths().keySet()) { - PathItem path = openAPI.getPaths().get(pathname); - if (path.readOperations() != null) { - for (Operation operation : path.readOperations()) { - if (operation.getTags() != null) { - List> tags = new ArrayList>(); - for (String tag : operation.getTags()) { - Map value = new HashMap(); - value.put("tag", tag); - value.put("hasMore", "true"); - tags.add(value); - } - if (tags.size() > 0) { - tags.get(tags.size() - 1).remove("hasMore"); - } - if (operation.getTags().size() > 0) { - String tag = operation.getTags().get(0); - operation.setTags(Arrays.asList(tag)); - } - operation.addExtension("x-tags", tags); + openAPI.getPaths() + .keySet() + .stream() + .map(pathname -> openAPI.getPaths().get(pathname)) + .filter(path -> path.readOperations() != null) + .flatMap(path -> path.readOperations().stream()).filter(operation -> operation.getTags() != null) + .forEach(operation -> { + List> tags = new ArrayList<>(); + for (String tag : operation.getTags()) { + Map value = new HashMap<>(); + value.put("tag", tag); + value.put("hasMore", "true"); + tags.add(value); } - } - } - } + if (tags.size() > 0) { + tags.get(tags.size() - 1).remove("hasMore"); + } + if (operation.getTags().size() > 0) { + String tag = operation.getTags().get(0); + operation.setTags(Arrays.asList(tag)); + } + operation.addExtension("x-tags", tags); + }); } } @@ -240,22 +237,19 @@ public void preprocessOpenAPI(OpenAPI openAPI) { public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { super.postProcessModelProperty(model, property); - if ("null".equals(property.example)) { + if ("null".equals(property.example)) property.example = null; - } //Add imports for Jackson if (!Boolean.TRUE.equals(model.isEnum)) { model.imports.add("JsonProperty"); - - if (Boolean.TRUE.equals(model.hasEnums)) { + if (Boolean.TRUE.equals(model.hasEnums)) model.imports.add("JsonValue"); - } - } else { // enum class + + } else { //Needed imports for Jackson's JsonCreator - if (additionalProperties.containsKey("jackson")) { + if (additionalProperties.containsKey("jackson")) model.imports.add("JsonCreator"); - } } } @@ -266,17 +260,17 @@ public Map postProcessModelsEnum(Map objs) { //Add imports for Jackson List> imports = (List>) objs.get("imports"); List models = (List) objs.get("models"); - for (Object _mo : models) { - Map mo = (Map) _mo; - CodegenModel cm = (CodegenModel) mo.get("model"); - // for enum model - if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) { - cm.imports.add(importMapping.get("JsonValue")); - Map item = new HashMap(); - item.put("import", importMapping.get("JsonValue")); - imports.add(item); - } - } + + models.stream() + .map(mo -> (Map) mo) + .map(mo -> (CodegenModel) mo.get("model")) + .filter(cm -> Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) + .forEach(cm -> { + cm.imports.add(importMapping.get("JsonValue")); + Map item = new HashMap<>(); + item.put("import", importMapping.get("JsonValue")); + imports.add(item); + }); return objs; } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache new file mode 100644 index 000000000000..8780f0939293 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache @@ -0,0 +1,31 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +{{=<% %>=}} +@RequestMapping("{openapi.<%title%>.base-path:<%>defaultBasePath%>}") +<%={{ }}=%> +{{#operations}} +class {{classname}}Controller { + +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache index fd900dcf7d66..eb52629b9f45 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache @@ -35,6 +35,7 @@ dependencies { compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") compile("org.jetbrains.kotlin:kotlin-reflect") compile("org.springframework.boot:spring-boot-starter-web") + compile("io.swagger:swagger-annotations:1.5.14") testCompile("org.springframework.boot:spring-boot-starter-test") { exclude(module = "junit") diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache new file mode 100644 index 000000000000..3c7185bd6289 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache @@ -0,0 +1 @@ +{{contextPath}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache index 0b4f3c62a3be..5f01dc8570ed 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache @@ -1,10 +1,12 @@ package {{basePackage}} import org.springframework.boot.runApplication +import org.springframework.context.annotation.ComponentScan import org.springframework.boot.autoconfigure.SpringBootApplication @SpringBootApplication +@ComponentScan(basePackages = arrayOf("{{basePackage}}", "{{apiPackage}}", "{{configPackage}}")) class Application fun main(args: Array) { From bf549e8417a46cee40e5ce5baf4e21eb87c71973 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Fri, 10 Aug 2018 12:32:56 +0100 Subject: [PATCH 07/39] Basic spring boot app generated with models and controllers --- .../languages/KotlinSpringServerCodegen.java | 146 ++++++++++++++---- .../main/resources/kotlin-spring/api.mustache | 53 +++++++ .../kotlin-spring/apiController.mustache | 31 ---- .../kotlin-spring/bodyParams.mustache | 1 + .../kotlin-spring/dataClass.mustache | 2 +- .../kotlin-spring/formParams.mustache | 1 + .../kotlin-spring/headerParams.mustache | 1 + .../spring-boot/openapi2SpringBoot.mustache | 2 +- .../kotlin-spring/optionalDataType.mustache | 1 + .../kotlin-spring/pathParams.mustache | 1 + .../kotlin-spring/queryParams.mustache | 1 + .../kotlin-spring/returnTypes.mustache | 1 + 12 files changed, 181 insertions(+), 60 deletions(-) delete mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/optionalDataType.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/returnTypes.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 14def5a94ab6..d69f2fde136f 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -1,5 +1,6 @@ package org.openapitools.codegen.languages; +import com.samskivert.mustache.Mustache; import io.swagger.v3.oas.models.OpenAPI; import org.openapitools.codegen.*; import org.openapitools.codegen.utils.URLPathUtils; @@ -9,6 +10,7 @@ import java.io.File; import java.net.URL; import java.util.*; +import java.util.regex.Matcher; /** * TODO Config: @@ -21,12 +23,23 @@ * isEnum * enumOuterClass * isEnum + * TODO Controller generation: + * - Handle implicit headers, also within api.mustache + * - Handle tags + * - If we handle optional, decide to make use of Java Optional, or Kotlin? */ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { private static Logger LOGGER = LoggerFactory.getLogger(KotlinSpringServerCodegen.class); + private static final HashSet VARIABLE_RESERVED_WORDS = + new HashSet(Arrays.asList( + "ApiClient", + "ApiException", + "ApiResponse" + )); + public static final String TITLE = "title"; public static final String SERVER_PORT = "serverPort"; public static final String BASE_PACKAGE = "basePackage"; @@ -43,6 +56,8 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { public KotlinSpringServerCodegen() { super(); + reservedWords.addAll(VARIABLE_RESERVED_WORDS); + outputFolder = "generated-code/kotlin-spring"; apiTestTemplateFiles.clear(); // TODO: add test template embeddedTemplateDir = templateDir = "kotlin-spring"; @@ -72,7 +87,7 @@ public KotlinSpringServerCodegen() { cliOptions.add(cliOpt); modelTemplateFiles.put("model.mustache", ".kt"); -// apiTemplateFiles.put("api.mustache", ".zz"); + apiTemplateFiles.put("api.mustache", ".kt"); } @Override @@ -149,8 +164,13 @@ public void processOpts() { if (library.equals(SPRING_BOOT)) { supportingFiles.add(new SupportingFile("openapi2SpringBoot.mustache", sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); - apiTemplateFiles.put("apiController.mustache", "Controller.kt"); } + + // add lambda for mustache templates + additionalProperties.put("lambdaEscapeDoubleQuote", + (Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("\"", Matcher.quoteReplacement("\\\"")))); + additionalProperties.put("lambdaRemoveLineBreak", + (Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("\\r|\\n", ""))); } public String getBasePackage() { @@ -177,6 +197,20 @@ public void setServerPort(String serverPort) { this.serverPort = serverPort; } + @Override + public String toModelName(final String name) { + // TODO This logic should be cleanup and moved to parent `AbstractKotlinCodegen`. See TODO in super.escapeReservedWord() + final String preProcessedName = super.toModelName(name); + + final String nameNoTicks = preProcessedName.replace("`", ""); + if (VARIABLE_RESERVED_WORDS.contains(nameNoTicks)) { + final String modelName = "Model" + nameNoTicks; + LOGGER.warn(nameNoTicks + " (reserved word) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + return preProcessedName; + } + @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); @@ -206,31 +240,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080)); } - if (openAPI.getPaths() != null) { - openAPI.getPaths() - .keySet() - .stream() - .map(pathname -> openAPI.getPaths().get(pathname)) - .filter(path -> path.readOperations() != null) - .flatMap(path -> path.readOperations().stream()).filter(operation -> operation.getTags() != null) - .forEach(operation -> { - List> tags = new ArrayList<>(); - for (String tag : operation.getTags()) { - Map value = new HashMap<>(); - value.put("tag", tag); - value.put("hasMore", "true"); - tags.add(value); - } - if (tags.size() > 0) { - tags.get(tags.size() - 1).remove("hasMore"); - } - if (operation.getTags().size() > 0) { - String tag = operation.getTags().get(0); - operation.setTags(Arrays.asList(tag)); - } - operation.addExtension("x-tags", tags); - }); - } + // TODO: Handle tags } @Override @@ -275,6 +285,88 @@ public Map postProcessModelsEnum(Map objs) { return objs; } + @Override + public Map postProcessOperationsWithModels(Map objs, List allModels) { + Map operations = (Map) objs.get("operations"); + if (operations != null) { + List ops = (List) operations.get("operation"); + ops.forEach(operation -> { + List responses = operation.responses; + if (responses != null) { + responses.forEach(resp -> { + + if ("0".equals(resp.code)) + resp.code = "200"; + + doDataTypeAssignment(resp.dataType, new DataTypeAssigner() { + @Override + public void setReturnType(final String returnType) { + resp.dataType = returnType; + } + + @Override + public void setReturnContainer(final String returnContainer) { + resp.containerType = returnContainer; + } + }); + }); + } + doDataTypeAssignment(operation.returnType, new DataTypeAssigner() { + + @Override + public void setReturnType(final String returnType) { + operation.returnType = returnType; + } + + @Override + public void setReturnContainer(final String returnContainer) { + operation.returnContainer = returnContainer; + } + }); +// if(implicitHeaders){ +// removeHeadersFromAllParams(operation.allParams); +// } + }); + } + + return objs; + } + + private interface DataTypeAssigner { + void setReturnType(String returnType); + + void setReturnContainer(String returnContainer); + } + + /** + * @param returnType The return type that needs to be converted + * @param dataTypeAssigner An object that will assign the data to the respective fields in the model. + */ + private void doDataTypeAssignment(String returnType, DataTypeAssigner dataTypeAssigner) { + final String rt = returnType; + if (rt == null) { + dataTypeAssigner.setReturnType("Unit"); + } else if (rt.startsWith("List")) { + int end = rt.lastIndexOf(">"); + if (end > 0) { + dataTypeAssigner.setReturnType(rt.substring("List<".length(), end).trim()); + dataTypeAssigner.setReturnContainer("List"); + } + } else if (rt.startsWith("Map")) { + int end = rt.lastIndexOf(">"); + if (end > 0) { + dataTypeAssigner.setReturnType(rt.substring("Map<".length(), end).split(",")[1].trim()); + dataTypeAssigner.setReturnContainer("Map"); + } + } else if (rt.startsWith("Set")) { + int end = rt.lastIndexOf(">"); + if (end > 0) { + dataTypeAssigner.setReturnType(rt.substring("Set<".length(), end).trim()); + dataTypeAssigner.setReturnContainer("Set"); + } + } + } + private static String sanitizeDirectory(String in) { return in.replace(".", File.separator); } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index e69de29bb2d1..95724dfc8553 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -0,0 +1,53 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +@Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API") +{{=<% %>=}} +@RequestMapping("\${openapi.<%title%>.base-path:<%>defaultBasePath%>}") +<%={{ }}=%> +{{#operations}} +class {{classname}}Controller { +{{#operation}} + + @ApiOperation( + value = "{{{summary}}}", + nickname = "{{{operationId}}}", + notes = "{{{notes}}}"{{#returnBaseType}}, + response = {{{returnBaseType}}}::class{{/returnBaseType}}{{#returnContainer}}, + responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, + authorizations = [{{#authMethods}}Authorization(value = "{{name}}"{{#isOAuth}}, scopes = [{{#scopes}}AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, {{/hasMore}}{{/scopes}}]{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}}]{{/hasAuthMethods}}) + @ApiResponses( + value = [{{#responses}}ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{baseType}}}::class{{/baseType}}{{#containerType}}, responseContainer = "{{{containerType}}}"{{/containerType}}){{#hasMore}},{{/hasMore}}{{/responses}}]) + @RequestMapping( + value = ["{{{path}}}"],{{#singleContentTypes}}{{#hasProduces}} + produces = "{{{vendorExtensions.x-accepts}}}", {{/hasProduces}}{{#hasConsumes}} + consumes = "{{{vendorExtensions.x-contentType}}}",{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}} + produces = [{{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}}], {{/hasProduces}}{{#hasConsumes}} + consumes = [{{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}],{{/hasConsumes}}{{/singleContentTypes}} + method = [RequestMethod.{{httpMethod}}]) + fun {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/allParams}}): ResponseEntity<{{>returnTypes}}> { + return ResponseEntity(HttpStatus.NOT_IMPLEMENTED) + } +{{/operation}} +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache deleted file mode 100644 index 8780f0939293..000000000000 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache +++ /dev/null @@ -1,31 +0,0 @@ -package {{package}} - -{{#imports}}import {{import}} -{{/imports}} -import io.swagger.annotations.* -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.stereotype.Controller -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestPart -import org.springframework.web.bind.annotation.RequestParam -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestHeader -import org.springframework.web.bind.annotation.RequestMethod -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.context.request.NativeWebRequest -import org.springframework.web.multipart.MultipartFile - -import kotlin.collections.List -import kotlin.collections.Map - -@Controller -{{=<% %>=}} -@RequestMapping("{openapi.<%title%>.base-path:<%>defaultBasePath%>}") -<%={{ }}=%> -{{#operations}} -class {{classname}}Controller { - -} -{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache new file mode 100644 index 000000000000..2a21dd26bb28 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache @@ -0,0 +1 @@ +{{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{^isContainer}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{/isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody {{paramName}}: {{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isListContainer}}Mono{{/isListContainer}}{{#isListContainer}}Flux{{/isListContainer}}<{{{baseType}}}>{{/reactive}}{{/isBodyParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache index 8a40b23e946c..4ee40aacbb83 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache @@ -4,7 +4,7 @@ * @param {{name}} {{{description}}} {{/vars}} */ -data class {{classname}} ( +data class {{classname}} {{#parent}} : {{{parent}}}{{/parent}} ( {{#requiredVars}} {{>dataClassReqVar}}{{^-last}}, {{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}}, diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache new file mode 100644 index 000000000000..6662feb09854 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache @@ -0,0 +1 @@ +{{#isFormParam}}{{^isFile}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{paramName}}: {{{dataType}}} {{/isFile}}{{#isFile}}@ApiParam(value = "file detail") {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart("file") {{baseName}}: MultipartFile{{/isFile}}{{/isFormParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache new file mode 100644 index 000000000000..7efa285b62ba --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache @@ -0,0 +1 @@ +{{#isHeaderParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestHeader(value="{{baseName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{paramName}}: {{>optionalDataType}}{{/isHeaderParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache index 5f01dc8570ed..ce92c49665ce 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache @@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication @SpringBootApplication -@ComponentScan(basePackages = arrayOf("{{basePackage}}", "{{apiPackage}}", "{{configPackage}}")) +@ComponentScan(basePackages = ["{{basePackage}}", "{{apiPackage}}", "{{configPackage}}"]) class Application fun main(args: Array) { diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/optionalDataType.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/optionalDataType.mustache new file mode 100644 index 000000000000..976950e27e88 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/optionalDataType.mustache @@ -0,0 +1 @@ +{{#useOptional}}{{#required}}{{{dataType}}}{{/required}}{{^required}}Optional<{{{dataType}}}>{{/required}}{{/useOptional}}{{^useOptional}}{{{dataType}}}{{/useOptional}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache new file mode 100644 index 000000000000..243c0eb46e0d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache @@ -0,0 +1 @@ +{{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambdaEscapeDoubleQuote}}{{{value}}}{{/lambdaEscapeDoubleQuote}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/enumVars}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathVariable("{{baseName}}") {{paramName}}: {{>optionalDataType}}{{/isPathParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache new file mode 100644 index 000000000000..e923f135f667 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache @@ -0,0 +1 @@ +{{#isQueryParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}) {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestParam(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{paramName}}: {{>optionalDataType}}{{/isQueryParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/returnTypes.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/returnTypes.mustache new file mode 100644 index 000000000000..67d79cc198ce --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/returnTypes.mustache @@ -0,0 +1 @@ +{{#isMapContainer}}{{#reactive}}Mono<{{/reactive}}Map{{/reactive}}>{{/isMapContainer}}{{#isListContainer}}{{#reactive}}Flux{{/reactive}}{{^reactive}}List{{/reactive}}<{{{returnType}}}>{{/isListContainer}}{{^returnContainer}}{{#reactive}}Mono<{{{returnType}}}>{{/reactive}}{{^reactive}}{{{returnType}}}{{/reactive}}{{/returnContainer}} \ No newline at end of file From 9b27b3c6e1319dd6b8c54a2c72d69bf37a82dbe8 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Fri, 10 Aug 2018 14:02:32 +0100 Subject: [PATCH 08/39] Added fix for type mapping in AbstractKotlinCodegen. Originally it was mapping list o kotlin.Array instead of kotlin.collections.List --- .../openapitools/codegen/languages/AbstractKotlinCodegen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index 774c96fe33fa..9c50f6080e10 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -164,7 +164,7 @@ public AbstractKotlinCodegen() { typeMapping.put("date", "java.time.LocalDateTime"); typeMapping.put("file", "java.io.File"); typeMapping.put("array", "kotlin.Array"); - typeMapping.put("list", "kotlin.Array"); + typeMapping.put("list", "kotlin.collections.List"); typeMapping.put("map", "kotlin.collections.Map"); typeMapping.put("object", "kotlin.Any"); typeMapping.put("binary", "kotlin.Array"); From d04d7dbd76f311750504afc77699cb903cdf86ac Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Fri, 10 Aug 2018 14:02:53 +0100 Subject: [PATCH 09/39] Fixed return type mapping --- .../languages/KotlinSpringServerCodegen.java | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index d69f2fde136f..1d06ff6ec748 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -19,10 +19,6 @@ * TODO Model generation: * - serializableModel by implementing java.io.Serializable * - enable optional bean validation using javax.validation.Valid (currently must be valid) - * - support enums in model generation: - * isEnum - * enumOuterClass - * isEnum * TODO Controller generation: * - Handle implicit headers, also within api.mustache * - Handle tags @@ -342,28 +338,21 @@ private interface DataTypeAssigner { * @param returnType The return type that needs to be converted * @param dataTypeAssigner An object that will assign the data to the respective fields in the model. */ - private void doDataTypeAssignment(String returnType, DataTypeAssigner dataTypeAssigner) { - final String rt = returnType; - if (rt == null) { + private void doDataTypeAssignment(final String returnType, DataTypeAssigner dataTypeAssigner) { + if (returnType == null) { dataTypeAssigner.setReturnType("Unit"); - } else if (rt.startsWith("List")) { - int end = rt.lastIndexOf(">"); + } else if (returnType.startsWith("kotlin.Array")) { + int end = returnType.lastIndexOf(">"); if (end > 0) { - dataTypeAssigner.setReturnType(rt.substring("List<".length(), end).trim()); + dataTypeAssigner.setReturnType(returnType.substring("kotlin.Array<".length(), end).trim()); dataTypeAssigner.setReturnContainer("List"); } - } else if (rt.startsWith("Map")) { - int end = rt.lastIndexOf(">"); + } else if (returnType.startsWith("kotlin.collections.Map")) { + int end = returnType.lastIndexOf(">"); if (end > 0) { - dataTypeAssigner.setReturnType(rt.substring("Map<".length(), end).split(",")[1].trim()); + dataTypeAssigner.setReturnType(returnType.substring("kotlin.collections.Map<".length(), end).split(",")[1].trim()); dataTypeAssigner.setReturnContainer("Map"); } - } else if (rt.startsWith("Set")) { - int end = rt.lastIndexOf(">"); - if (end > 0) { - dataTypeAssigner.setReturnType(rt.substring("Set<".length(), end).trim()); - dataTypeAssigner.setReturnContainer("Set"); - } } } From 0dd39a96552f092b88644440f65c658a5d8cd47a Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Fri, 10 Aug 2018 14:50:21 +0100 Subject: [PATCH 10/39] Sorted bash springboot petstore generator script --- ...rver-petstore.sh => kotlin-springboot-petstore-server.sh} | 5 +++-- ...er-petstore.bat => kotlin-springboot-petstore-server.bat} | 0 2 files changed, 3 insertions(+), 2 deletions(-) rename bin/{kotlin-spring-server-petstore.sh => kotlin-springboot-petstore-server.sh} (75%) rename bin/windows/{kotlin-spring-server-petstore.bat => kotlin-springboot-petstore-server.bat} (100%) diff --git a/bin/kotlin-spring-server-petstore.sh b/bin/kotlin-springboot-petstore-server.sh similarity index 75% rename from bin/kotlin-spring-server-petstore.sh rename to bin/kotlin-springboot-petstore-server.sh index 7fd1703cd45b..4cbb71a26a38 100755 --- a/bin/kotlin-spring-server-petstore.sh +++ b/bin/kotlin-springboot-petstore-server.sh @@ -1,6 +1,7 @@ #!/bin/sh SCRIPT="$0" +echo "# START SCRIPT: $SCRIPT" while [ -h "$SCRIPT" ] ; do ls=$(ls -ld "$SCRIPT") @@ -26,6 +27,6 @@ fi # if you've executed sbt assembly previously it will use that instead. export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g kotlin-spring -o samples/server/petstore/kotlin-spring" +ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g kotlin-spring -o samples/server/petstore/kotlin-springboot --additional-properties=library=spring-boot" -java ${JAVA_OPTS} -jar ${executable} ${ags} +java $JAVA_OPTS -jar $executable $ags diff --git a/bin/windows/kotlin-spring-server-petstore.bat b/bin/windows/kotlin-springboot-petstore-server.bat similarity index 100% rename from bin/windows/kotlin-spring-server-petstore.bat rename to bin/windows/kotlin-springboot-petstore-server.bat From ecc14aad612045a21ab6031bc8f499d5a52cf303 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Fri, 10 Aug 2018 16:51:44 +0100 Subject: [PATCH 11/39] Implemented toVarName in AbstractKotlinCodegen to better handle some edgecases --- .../languages/AbstractKotlinCodegen.java | 51 +++++++++++++++++-- .../languages/KotlinSpringServerCodegen.java | 3 +- .../main/resources/kotlin-spring/README.md | 0 .../kotlin-spring/dataClass.mustache | 2 +- .../kotlin-spring/dataClassOptVar.mustache | 2 +- .../kotlin-spring/dataClassReqVar.mustache | 2 +- 6 files changed, 51 insertions(+), 9 deletions(-) delete mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/README.md diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index 9c50f6080e10..b86b4045f405 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -28,11 +28,7 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map; +import java.util.*; public abstract class AbstractKotlinCodegen extends DefaultCodegen implements CodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractKotlinCodegen.class); @@ -577,4 +573,49 @@ public String toEnumValue(String value, String datatype) { public boolean isDataTypeString(final String dataType) { return "String".equals(dataType) || "kotlin.String".equals(dataType); } + + @Override + public String toVarName(String name) { + // sanitize name + name = sanitizeName(name, "\\W-[\\$]"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + if (name.toLowerCase().matches("^_*class$")) + return "propertyClass"; + + if ("_".equals(name)) + name = "_u"; + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) + return name; + + if (startsWithTwoUppercaseLetters(name)) + name = name.substring(0, 2).toLowerCase() + name.substring(2); + + // If name contains special chars -> replace them. + if ((((CharSequence) name).chars().anyMatch(character -> specialCharReplacements.keySet().contains("" + ((char) character))))) { + List allowedCharacters = new ArrayList<>(); + allowedCharacters.add("_"); + allowedCharacters.add("$"); + name = escapeSpecialCharacters(name, allowedCharacters, "_"); + } + + // camelize (lower first character) the variable name + // pet_id => petId + name = camelize(name, true); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) + name = escapeReservedWord(name); + + return name; + } + + private boolean startsWithTwoUppercaseLetters(String name) { + boolean startsWithTwoUppercaseLetters = false; + if (name.length() > 1) { + startsWithTwoUppercaseLetters = name.substring(0, 2).equals(name.substring(0, 2).toUpperCase()); + } + return startsWithTwoUppercaseLetters; + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 1d06ff6ec748..27075b3cafb8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -15,7 +15,8 @@ /** * TODO Config: * - handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" - * - integrate Spring Fox + * TODO Config: + * - generate README.md * TODO Model generation: * - serializableModel by implementing java.io.Serializable * - enable optional bean validation using javax.validation.Valid (currently must be valid) diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/README.md b/modules/openapi-generator/src/main/resources/kotlin-spring/README.md deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache index 4ee40aacbb83..8a40b23e946c 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache @@ -4,7 +4,7 @@ * @param {{name}} {{{description}}} {{/vars}} */ -data class {{classname}} {{#parent}} : {{{parent}}}{{/parent}} ( +data class {{classname}} ( {{#requiredVars}} {{>dataClassReqVar}}{{^-last}}, {{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}}, diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache index 32f9a32a98db..b87ec9680348 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache @@ -1,4 +1,4 @@ {{#description}} /* {{{description}}} */ {{/description}} - @JsonProperty("{{{name}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file + @JsonProperty("{{{baseName}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache index 4aa15c8b05a2..2a6cb7bb7004 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache @@ -1,4 +1,4 @@ {{#description}} /* {{{description}}} */ {{/description}} - @JsonProperty("{{{name}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}} \ No newline at end of file + @JsonProperty("{{{baseName}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}} \ No newline at end of file From f1179dade10822d2f2c8f0ecbd4108026d468264 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Fri, 10 Aug 2018 17:21:43 +0100 Subject: [PATCH 12/39] Checking for reserved words or numerical starting class names in AbstractKotlinCodegen --- .../codegen/languages/AbstractKotlinCodegen.java | 14 ++++++++++++-- .../languages/KotlinSpringServerCodegen.java | 14 -------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index b86b4045f405..c168223d9471 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -469,8 +469,18 @@ public String toModelName(final String name) { // Camelize name of nested properties modifiedName = camelize(modifiedName); - if (reservedWords.contains(modifiedName)) { - modifiedName = escapeReservedWord(modifiedName); + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(modifiedName)) { + final String modelName = "Model" + modifiedName; + LOGGER.warn(modifiedName + " (reserved word) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + // model name starts with number + if (modifiedName.matches("^\\d.*")) { + final String modelName = "Model" + modifiedName; // e.g. 200Response => Model200Response (after camelize) + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName); + return modelName; } return titleCase(modifiedName); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 27075b3cafb8..e488598376bb 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -194,20 +194,6 @@ public void setServerPort(String serverPort) { this.serverPort = serverPort; } - @Override - public String toModelName(final String name) { - // TODO This logic should be cleanup and moved to parent `AbstractKotlinCodegen`. See TODO in super.escapeReservedWord() - final String preProcessedName = super.toModelName(name); - - final String nameNoTicks = preProcessedName.replace("`", ""); - if (VARIABLE_RESERVED_WORDS.contains(nameNoTicks)) { - final String modelName = "Model" + nameNoTicks; - LOGGER.warn(nameNoTicks + " (reserved word) cannot be used as model name. Renamed to " + modelName); - return modelName; - } - return preProcessedName; - } - @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); From 6dd461443069c8123a09c9f601f2ebd3dd41f9ff Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Fri, 10 Aug 2018 18:08:21 +0100 Subject: [PATCH 13/39] Implemented toOperationId in AbstractKotlinCodegen --- .../languages/AbstractKotlinCodegen.java | 31 +++++++++++++++++++ .../languages/KotlinSpringServerCodegen.java | 12 ++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index c168223d9471..ccafd073cd20 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -19,6 +19,7 @@ import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.CliOption; import org.openapitools.codegen.CodegenConfig; import org.openapitools.codegen.CodegenConstants; @@ -486,6 +487,36 @@ public String toModelName(final String name) { return titleCase(modifiedName); } + /** + * Return the operation ID (method name) + * + * @param operationId operation ID + * @return the sanitized method name + */ + @Override + public String toOperationId(String operationId) { + // throw exception if method name is empty + if (StringUtils.isEmpty(operationId)) + throw new RuntimeException("Empty method/operation name (operationId) not allowed"); + + operationId = camelize(sanitizeName(operationId), true); + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + String newOperationId = camelize("call_" + operationId, true); + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId); + return newOperationId; + } + + // operationId starts with a number + if (operationId.matches("^\\d.*")) { + LOGGER.warn(operationId + " (starting with a number) cannot be used as method sname. Renamed to " + camelize("call_" + operationId), true); + operationId = camelize("call_" + operationId, true); + } + + return operationId; + } + @Override public String toModelFilename(String name) { // Should be the same as the model name diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index e488598376bb..38e3c5f6c3a4 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -15,7 +15,10 @@ /** * TODO Config: * - handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" - * TODO Config: + * - Option to generate gradle + * - Generate POM + * - Other cleanups + * TODO Readme: * - generate README.md * TODO Model generation: * - serializableModel by implementing java.io.Serializable @@ -24,6 +27,13 @@ * - Handle implicit headers, also within api.mustache * - Handle tags * - If we handle optional, decide to make use of Java Optional, or Kotlin? + * - Use RestController instead of Controller annotation (see PR #571 for more info) + * TODO General fixes + * - Inheritance + * - Enum Arrays + * - Map of enums and indirect maps + * - Special model names + * - Some types not correctly being mapped to primitives */ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { From d536bf216c4ebb7d9e0004428474f1d8592df524 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Mon, 13 Aug 2018 14:23:26 +0100 Subject: [PATCH 14/39] Fixed types that were not correctly being mapped to primitives (byte / arrayOf / mapOf) --- .../languages/AbstractKotlinCodegen.java | 20 ++++++++++++++++--- .../languages/KotlinSpringServerCodegen.java | 11 +++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index ccafd073cd20..332dcb3b861a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -52,6 +52,7 @@ public AbstractKotlinCodegen() { languageSpecificPrimitives = new HashSet(Arrays.asList( "kotlin.Byte", + "kotlin.ByteArray", "kotlin.Short", "kotlin.Int", "kotlin.Long", @@ -136,6 +137,7 @@ public AbstractKotlinCodegen() { defaultIncludes = new HashSet(Arrays.asList( "kotlin.Byte", + "kotlin.ByteArray", "kotlin.Short", "kotlin.Int", "kotlin.Long", @@ -156,6 +158,7 @@ public AbstractKotlinCodegen() { typeMapping.put("float", "kotlin.Float"); typeMapping.put("long", "kotlin.Long"); typeMapping.put("double", "kotlin.Double"); + typeMapping.put("ByteArray", "kotlin.ByteArray"); typeMapping.put("number", "java.math.BigDecimal"); typeMapping.put("date-time", "java.time.LocalDateTime"); typeMapping.put("date", "java.time.LocalDateTime"); @@ -168,9 +171,9 @@ public AbstractKotlinCodegen() { typeMapping.put("Date", "java.time.LocalDateTime"); typeMapping.put("DateTime", "java.time.LocalDateTime"); - instantiationTypes.put("array", "arrayOf"); - instantiationTypes.put("list", "arrayOf"); - instantiationTypes.put("map", "mapOf"); + instantiationTypes.put("array", "kotlin.arrayOf"); + instantiationTypes.put("list", "kotlin.arrayOf"); + instantiationTypes.put("map", "kotlin.mapOf"); importMapping = new HashMap(); importMapping.put("BigDecimal", "java.math.BigDecimal"); @@ -615,6 +618,17 @@ public boolean isDataTypeString(final String dataType) { return "String".equals(dataType) || "kotlin.String".equals(dataType); } + @Override + public String toParamName(String name) { + // to avoid conflicts with 'callback' parameter for async call + if ("callback".equals(name)) { + return "paramCallback"; + } + + // should be the same as variable name + return toVarName(name); + } + @Override public String toVarName(String name) { // sanitize name diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 38e3c5f6c3a4..08a90aa5ad08 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -14,26 +14,27 @@ /** * TODO Config: - * - handle "INVOKER_PACKAGE" and "HIDE_GENERATION_TIMESTAMP" + * - handle INVOKER_PACKAGE * - Option to generate gradle * - Generate POM * - Other cleanups * TODO Readme: * - generate README.md * TODO Model generation: - * - serializableModel by implementing java.io.Serializable * - enable optional bean validation using javax.validation.Valid (currently must be valid) * TODO Controller generation: * - Handle implicit headers, also within api.mustache - * - Handle tags * - If we handle optional, decide to make use of Java Optional, or Kotlin? * - Use RestController instead of Controller annotation (see PR #571 for more info) * TODO General fixes - * - Inheritance * - Enum Arrays * - Map of enums and indirect maps * - Special model names - * - Some types not correctly being mapped to primitives + * - Inheritance + * TODO Other + * - Split implementation with controllers + * - Remove swagger annotations + * - Base types for oneOf (see inheritance) */ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { From 557561a1fc8a8b7a51e38f51cbcd6e1a701ae148 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Mon, 13 Aug 2018 16:15:47 +0100 Subject: [PATCH 15/39] Escaping dollar symbols in function names --- .../codegen/languages/AbstractKotlinCodegen.java | 6 +++--- .../codegen/languages/KotlinSpringServerCodegen.java | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index 332dcb3b861a..0d3907aa31c8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -632,7 +632,7 @@ public String toParamName(String name) { @Override public String toVarName(String name) { // sanitize name - name = sanitizeName(name, "\\W-[\\$]"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + name = sanitizeName(name, "\\W-[\\$]"); if (name.toLowerCase().matches("^_*class$")) return "propertyClass"; @@ -659,8 +659,8 @@ public String toVarName(String name) { // pet_id => petId name = camelize(name, true); - // for reserved word or word starting with number, append _ - if (isReservedWord(name) || name.matches("^\\d.*")) + // for reserved word or word starting with number or containing dollar symbol, escape it + if (isReservedWord(name) || name.matches("(^\\d.*)|(.*[$].*)")) name = escapeReservedWord(name); return name; diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 08a90aa5ad08..8e439de1fbd7 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -132,7 +132,6 @@ public void processOpts() { // Jackson import mappings importMapping.put("JsonValue", "com.fasterxml.jackson.annotation.JsonValue"); importMapping.put("JsonCreator", "com.fasterxml.jackson.annotation.JsonCreator"); - importMapping.put("SerializedName", "com.google.gson.annotations.SerializedName"); importMapping.put("JsonProperty", "com.fasterxml.jackson.annotation.JsonProperty"); importMapping.put("JsonSubTypes", "com.fasterxml.jackson.annotation.JsonSubTypes"); importMapping.put("JsonTypeInfo", "com.fasterxml.jackson.annotation.JsonTypeInfo"); From d692efd55bf418b515f6fc91f7ab37ccd8186f42 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Mon, 13 Aug 2018 18:29:54 +0100 Subject: [PATCH 16/39] Added support for outter enum classes --- .../codegen/languages/KotlinSpringServerCodegen.java | 5 ++--- .../src/main/resources/kotlin-spring/dataClass.mustache | 4 ++-- .../src/main/resources/kotlin-spring/enumClass.mustache | 9 +++++++++ .../src/main/resources/kotlin-spring/model.mustache | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/enumClass.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 8e439de1fbd7..dc53bac09b21 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -27,9 +27,8 @@ * - If we handle optional, decide to make use of Java Optional, or Kotlin? * - Use RestController instead of Controller annotation (see PR #571 for more info) * TODO General fixes - * - Enum Arrays - * - Map of enums and indirect maps - * - Special model names + * - Generated Enum to support Arrays / Maps / Collections + * - Ensure value passed into JsonProperty is a String (see generated SpecialModelname.kt and EnumTest.kt) with escaped $ sign * - Inheritance * TODO Other * - Split implementation with controllers diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache index 8a40b23e946c..aead29788015 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache @@ -16,9 +16,9 @@ data class {{classname}} ( * {{{description}}} * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} */ - enum class {{nameInCamelCase}}(val value: {{dataType}}) { + enum class {{nameInCamelCase}}(val value: {{{dataType}}}) { {{#allowableValues}}{{#enumVars}} - @JsonProperty({{{value}}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} + @JsonProperty({{{value}}}) {{{name}}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} {{/enumVars}}{{/allowableValues}} } {{/isEnum}}{{/vars}}{{/hasEnums}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/enumClass.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/enumClass.mustache new file mode 100644 index 000000000000..2f24a1de76b2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/enumClass.mustache @@ -0,0 +1,9 @@ +/** +* {{{description}}} +* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} +*/ +enum class {{classname}}(val value: {{dataType}}) { +{{#allowableValues}}{{#enumVars}} + {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} +{{/enumVars}}{{/allowableValues}} +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache index e6baa088ae95..5335b9c0caaa 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache @@ -8,6 +8,6 @@ import javax.validation.constraints.* {{#models}} {{#model}} -{{>dataClass}} +{{#isEnum}}{{>enumClass}}{{/isEnum}}{{^isEnum}}{{>dataClass}}{{/isEnum}} {{/model}} {{/models}} From 6e4a4fe22c512e78f7d7b79a5a068bc8e229aa42 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 14 Aug 2018 16:53:48 +0100 Subject: [PATCH 17/39] Added basic support for generating services --- .../languages/KotlinSpringServerCodegen.java | 14 ++++++++--- .../main/resources/kotlin-spring/api.mustache | 5 ++-- .../kotlin-spring/exceptions.mustache | 24 +++++++++++++++++++ .../resources/kotlin-spring/service.mustache | 13 ++++++++++ .../kotlin-spring/serviceImpl.mustache | 17 +++++++++++++ 5 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/service.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/serviceImpl.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index dc53bac09b21..2cb1ca1a5cad 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -92,9 +92,6 @@ public KotlinSpringServerCodegen() { cliOpt.setDefault(SPRING_BOOT); cliOpt.setEnum(supportedLibraries); cliOptions.add(cliOpt); - - modelTemplateFiles.put("model.mustache", ".kt"); - apiTemplateFiles.put("api.mustache", ".kt"); } @Override @@ -168,8 +165,18 @@ public void processOpts() { supportingFiles.add(new SupportingFile("application.mustache", resourceFolder, "application.yaml")); if (library.equals(SPRING_BOOT)) { + LOGGER.info("Setup code generator for Kotlin Spring Boot"); + + modelTemplateFiles.put("model.mustache", ".kt"); + apiTemplateFiles.put("api.mustache", ".kt"); + apiTemplateFiles.put("service.mustache", "Service.kt"); + apiTemplateFiles.put("serviceImpl.mustache", "ServiceImpl.kt"); + supportingFiles.add(new SupportingFile("openapi2SpringBoot.mustache", sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); + + supportingFiles.add(new SupportingFile("exceptions.mustache", + sanitizeDirectory(sourceFolder + File.separator + apiPackage), "Exceptions.kt")); } // add lambda for mustache templates @@ -253,6 +260,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert if (additionalProperties.containsKey("jackson")) model.imports.add("JsonCreator"); } + } @Override diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index 95724dfc8553..d7d537987c34 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile +import org.springframework.beans.factory.annotation.Autowired import kotlin.collections.List import kotlin.collections.Map @@ -26,7 +27,7 @@ import kotlin.collections.Map @RequestMapping("\${openapi.<%title%>.base-path:<%>defaultBasePath%>}") <%={{ }}=%> {{#operations}} -class {{classname}}Controller { +class {{classname}}Controller(@Autowired(required = true) val service: {{classname}}Service) { {{#operation}} @ApiOperation( @@ -46,7 +47,7 @@ class {{classname}}Controller { consumes = [{{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}],{{/hasConsumes}}{{/singleContentTypes}} method = [RequestMethod.{{httpMethod}}]) fun {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/allParams}}): ResponseEntity<{{>returnTypes}}> { - return ResponseEntity(HttpStatus.NOT_IMPLEMENTED) + return ResponseEntity(service.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}), HttpStatus.OK) } {{/operation}} } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache new file mode 100644 index 000000000000..8aa816faefab --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache @@ -0,0 +1,24 @@ +package {{apiPackage}} + +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ControllerAdvice +import org.springframework.web.bind.annotation.ExceptionHandler +import javax.servlet.http.HttpServletRequest + +sealed class ApiException(msg: String, val code: Int) : Exception(msg) + +class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) + + +@ControllerAdvice +class DefaultExceptionHandler { + + @ExceptionHandler(value = [NotFoundException::class]) + fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.valueOf(ex.code)) + + @ExceptionHandler(value = [NotImplementedError::class]) + fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.NOT_IMPLEMENTED) +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/service.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/service.mustache new file mode 100644 index 000000000000..32bb190ea6b4 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/service.mustache @@ -0,0 +1,13 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} + +{{#operations}} +interface {{classname}}Service { +{{#operation}} + + fun {{operationId}}({{#allParams}}{{paramName}}: {{^isFile}}{{>optionalDataType}}{{/isFile}}{{#isFile}}org.springframework.web.multipart.MultipartFile{{/isFile}}{{#hasMore}},{{/hasMore}}{{/allParams}}): {{>returnTypes}} +{{/operation}} +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/serviceImpl.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/serviceImpl.mustache new file mode 100644 index 000000000000..d3dcedb061e2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/serviceImpl.mustache @@ -0,0 +1,17 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} +import org.springframework.stereotype.Service + +@Service +{{#operations}} +class {{classname}}ServiceImpl : {{classname}}Service { +{{#operation}} + + override fun {{operationId}}({{#allParams}}{{paramName}}: {{^isFile}}{{>optionalDataType}}{{/isFile}}{{#isFile}}org.springframework.web.multipart.MultipartFile{{/isFile}}{{#hasMore}},{{/hasMore}}{{/allParams}}): {{>returnTypes}} { + TODO("Implement me") + } +{{/operation}} +} +{{/operations}} From 4d63f29342e2c59ae8c64bf768a7d7377c44bf04 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 14 Aug 2018 18:16:02 +0100 Subject: [PATCH 18/39] Removed option for generated config package. Added option to enable/disable generated global exception handler --- .../languages/KotlinSpringServerCodegen.java | 99 ++++++++++--------- ...ustache => springBootApplication.mustache} | 2 +- .../spring/KotlinSpringServerCodegenTest.java | 16 +-- 3 files changed, 62 insertions(+), 55 deletions(-) rename modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/{openapi2SpringBoot.mustache => springBootApplication.mustache} (93%) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 2cb1ca1a5cad..973143a57d79 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -31,7 +31,6 @@ * - Ensure value passed into JsonProperty is a String (see generated SpecialModelname.kt and EnumTest.kt) with escaped $ sign * - Inheritance * TODO Other - * - Split implementation with controllers * - Remove swagger annotations * - Base types for oneOf (see inheritance) */ @@ -50,15 +49,14 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { public static final String TITLE = "title"; public static final String SERVER_PORT = "serverPort"; public static final String BASE_PACKAGE = "basePackage"; - public static final String CONFIG_PACKAGE = "configPackage"; public static final String SPRING_BOOT = "spring-boot"; + public static final String EXCEPTION_HANDLER = "exceptionHandler"; - protected String resourceFolder = "src/main/resources"; - - protected String basePackage; - protected String configPackage; - protected String serverPort = "8080"; - protected String title = "OpenAPI Kotlin Spring"; + private String basePackage; + private String serverPort = "8080"; + private String title = "OpenAPI Kotlin Spring"; + private String resourceFolder = "src/main/resources"; + private boolean exceptionHandler = true; public KotlinSpringServerCodegen() { super(); @@ -73,17 +71,16 @@ public KotlinSpringServerCodegen() { basePackage = "org.openapitools"; apiPackage = "org.openapitools.api"; modelPackage = "org.openapitools.model"; - configPackage = "org.openapitools.conf"; // spring uses the jackson lib additionalProperties.put("jackson", "true"); addOption(TITLE, "server title name or client service name", title); addOption(BASE_PACKAGE, "base package for generated code", basePackage); - addOption(CONFIG_PACKAGE, "configuration package for generated code", configPackage); addOption(SERVER_PORT, "configuration the port in which the sever is to run on", serverPort); addOption(CodegenConstants.MODEL_PACKAGE, "model package for generated code", modelPackage); addOption(CodegenConstants.API_PACKAGE, "api package for generated code", apiPackage); + addSwitch(EXCEPTION_HANDLER, "generate default global exception handlers", exceptionHandler); supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); setLibrary(SPRING_BOOT); @@ -94,6 +91,38 @@ public KotlinSpringServerCodegen() { cliOptions.add(cliOpt); } + public String getResourceFolder() { + return this.resourceFolder; + } + + public void setResourceFolder(String resourceFolder) { + this.resourceFolder = resourceFolder; + } + + public String getBasePackage() { + return this.basePackage; + } + + public void setBasePackage(String basePackage) { + this.basePackage = basePackage; + } + + public String getServerPort() { + return this.serverPort; + } + + public void setServerPort(String serverPort) { + this.serverPort = serverPort; + } + + public boolean getExceptionHandler() { + return this.exceptionHandler; + } + + public void setExceptionHandler(boolean exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + @Override public CodegenType getTag() { return CodegenType.SERVER; @@ -154,29 +183,31 @@ public void processOpts() { additionalProperties.put(SERVER_PORT, serverPort); } - if (additionalProperties.containsKey(CONFIG_PACKAGE)) { - this.setConfigPackage((String) additionalProperties.get(CONFIG_PACKAGE)); + if (additionalProperties.containsKey(EXCEPTION_HANDLER)) { + this.setExceptionHandler(Boolean.valueOf(additionalProperties.get(EXCEPTION_HANDLER).toString())); } else { - additionalProperties.put(CONFIG_PACKAGE, configPackage); + additionalProperties.put(EXCEPTION_HANDLER, exceptionHandler); } supportingFiles.add(new SupportingFile("buildGradleKts.mustache", "", "build.gradle.kts")); supportingFiles.add(new SupportingFile("settingsGradle.mustache", "", "settings.gradle")); supportingFiles.add(new SupportingFile("application.mustache", resourceFolder, "application.yaml")); + modelTemplateFiles.put("model.mustache", ".kt"); + apiTemplateFiles.put("api.mustache", ".kt"); + apiTemplateFiles.put("service.mustache", "Service.kt"); + apiTemplateFiles.put("serviceImpl.mustache", "ServiceImpl.kt"); + + if (this.exceptionHandler) { + supportingFiles.add(new SupportingFile("exceptions.mustache", + sanitizeDirectory(sourceFolder + File.separator + apiPackage), "Exceptions.kt")); + } + if (library.equals(SPRING_BOOT)) { LOGGER.info("Setup code generator for Kotlin Spring Boot"); - modelTemplateFiles.put("model.mustache", ".kt"); - apiTemplateFiles.put("api.mustache", ".kt"); - apiTemplateFiles.put("service.mustache", "Service.kt"); - apiTemplateFiles.put("serviceImpl.mustache", "ServiceImpl.kt"); - - supportingFiles.add(new SupportingFile("openapi2SpringBoot.mustache", + supportingFiles.add(new SupportingFile("springBootApplication.mustache", sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); - - supportingFiles.add(new SupportingFile("exceptions.mustache", - sanitizeDirectory(sourceFolder + File.separator + apiPackage), "Exceptions.kt")); } // add lambda for mustache templates @@ -186,30 +217,6 @@ public void processOpts() { (Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("\\r|\\n", ""))); } - public String getBasePackage() { - return this.basePackage; - } - - public void setBasePackage(String basePackage) { - this.basePackage = basePackage; - } - - public String getConfigPackage() { - return this.configPackage; - } - - public void setConfigPackage(String configPackage) { - this.configPackage = configPackage; - } - - public String getServerPort() { - return this.serverPort; - } - - public void setServerPort(String serverPort) { - this.serverPort = serverPort; - } - @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/springBootApplication.mustache similarity index 93% rename from modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache rename to modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/springBootApplication.mustache index ce92c49665ce..5b0d62ebf0af 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/openapi2SpringBoot.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/springBootApplication.mustache @@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication @SpringBootApplication -@ComponentScan(basePackages = ["{{basePackage}}", "{{apiPackage}}", "{{configPackage}}"]) +@ComponentScan(basePackages = ["{{basePackage}}", "{{apiPackage}}", "{{modelPackage}}"]) class Application fun main(args: Array) { diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index f09acc57aec4..4fec2d09f1bb 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -20,14 +20,15 @@ public void testInitialConfigValues() throws Exception { openAPI.setInfo(new Info()); codegen.preprocessOpenAPI(openAPI); + Assert.assertEquals(codegen.getLibrary(), KotlinSpringServerCodegen.SPRING_BOOT); + Assert.assertTrue(codegen.supportedLibraries().containsKey(KotlinSpringServerCodegen.SPRING_BOOT)); + Assert.assertEquals(codegen.modelPackage(), "org.openapitools.model"); Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.MODEL_PACKAGE), "org.openapitools.model"); Assert.assertEquals(codegen.apiPackage(), "org.openapitools.api"); Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "org.openapitools.api"); Assert.assertEquals(codegen.getBasePackage(), "org.openapitools"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "org.openapitools"); - Assert.assertEquals(codegen.getConfigPackage(), "org.openapitools.conf"); - Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.CONFIG_PACKAGE), "org.openapitools.conf"); Assert.assertEquals(codegen.getServerPort(), "8080"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8080"); } @@ -38,8 +39,8 @@ public void testSettersForConfigValues() throws Exception { codegen.setModelPackage("xx.yyyyyyyy.model"); codegen.setApiPackage("xx.yyyyyyyy.api"); codegen.setBasePackage("xx.yyyyyyyy.base"); - codegen.setConfigPackage("xx.yyyyyyyy.config"); codegen.setServerPort("8181"); + codegen.setExceptionHandler(false); codegen.processOpts(); Assert.assertEquals(codegen.modelPackage(), "xx.yyyyyyyy.model"); @@ -48,10 +49,10 @@ public void testSettersForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "xx.yyyyyyyy.api"); Assert.assertEquals(codegen.getBasePackage(), "xx.yyyyyyyy.base"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "xx.yyyyyyyy.base"); - Assert.assertEquals(codegen.getConfigPackage(), "xx.yyyyyyyy.config"); - Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.CONFIG_PACKAGE), "xx.yyyyyyyy.config"); Assert.assertEquals(codegen.getServerPort(), "8181"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8181"); + Assert.assertFalse(codegen.getExceptionHandler()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); } @Test @@ -60,8 +61,8 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "xyz.yyyyy.mmmmm.model"); codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "xyz.yyyyy.aaaaa.api"); codegen.additionalProperties().put(KotlinSpringServerCodegen.BASE_PACKAGE, "xyz.yyyyy.bbbb.base"); - codegen.additionalProperties().put(KotlinSpringServerCodegen.CONFIG_PACKAGE, "xyz.yyyyy.cccc.config"); codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVER_PORT, "8088"); + codegen.additionalProperties().put(KotlinSpringServerCodegen.EXCEPTION_HANDLER, false); codegen.processOpts(); final OpenAPI openAPI = new OpenAPI(); @@ -76,9 +77,8 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "xyz.yyyyy.aaaaa.api"); Assert.assertEquals(codegen.getBasePackage(), "xyz.yyyyy.bbbb.base"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "xyz.yyyyy.bbbb.base"); - Assert.assertEquals(codegen.getConfigPackage(), "xyz.yyyyy.cccc.config"); - Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.CONFIG_PACKAGE), "xyz.yyyyy.cccc.config"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.TITLE), "someTest"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8088"); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); } } From 0eee4240c5f1b30c96de3aee68d3eeeae400bdd6 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 15 Aug 2018 12:17:08 +0100 Subject: [PATCH 19/39] Added configuration option to generate gradle. Generated maven pom.xml file as default --- .../languages/KotlinSpringServerCodegen.java | 35 ++++-- .../libraries/spring-boot/pom.mustache | 103 ++++++++++++++++++ .../spring/KotlinSpringServerCodegenTest.java | 7 ++ 3 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 973143a57d79..729e2287028a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -15,16 +15,15 @@ /** * TODO Config: * - handle INVOKER_PACKAGE - * - Option to generate gradle - * - Generate POM - * - Other cleanups + * - Option to generate services + * - Option to generate service implementations + * - Option to generate default exception handlers + * - Option to generate swagger annotations * TODO Readme: * - generate README.md * TODO Model generation: * - enable optional bean validation using javax.validation.Valid (currently must be valid) * TODO Controller generation: - * - Handle implicit headers, also within api.mustache - * - If we handle optional, decide to make use of Java Optional, or Kotlin? * - Use RestController instead of Controller annotation (see PR #571 for more info) * TODO General fixes * - Generated Enum to support Arrays / Maps / Collections @@ -51,12 +50,14 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { public static final String BASE_PACKAGE = "basePackage"; public static final String SPRING_BOOT = "spring-boot"; public static final String EXCEPTION_HANDLER = "exceptionHandler"; + public static final String GRADLE_BUILD_FILE = "gradleBuildFile"; private String basePackage; private String serverPort = "8080"; private String title = "OpenAPI Kotlin Spring"; private String resourceFolder = "src/main/resources"; private boolean exceptionHandler = true; + private boolean gradleBuildFile = true; public KotlinSpringServerCodegen() { super(); @@ -81,6 +82,7 @@ public KotlinSpringServerCodegen() { addOption(CodegenConstants.MODEL_PACKAGE, "model package for generated code", modelPackage); addOption(CodegenConstants.API_PACKAGE, "api package for generated code", apiPackage); addSwitch(EXCEPTION_HANDLER, "generate default global exception handlers", exceptionHandler); + addSwitch(GRADLE_BUILD_FILE, "generate a gradle build file using the Kotlin DSL", gradleBuildFile); supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); setLibrary(SPRING_BOOT); @@ -123,6 +125,14 @@ public void setExceptionHandler(boolean exceptionHandler) { this.exceptionHandler = exceptionHandler; } + public boolean getGradleBuildFile() { + return this.gradleBuildFile; + } + + public void setGradleBuildFile(boolean gradleBuildFile) { + this.gradleBuildFile = gradleBuildFile; + } + @Override public CodegenType getTag() { return CodegenType.SERVER; @@ -189,9 +199,11 @@ public void processOpts() { additionalProperties.put(EXCEPTION_HANDLER, exceptionHandler); } - supportingFiles.add(new SupportingFile("buildGradleKts.mustache", "", "build.gradle.kts")); - supportingFiles.add(new SupportingFile("settingsGradle.mustache", "", "settings.gradle")); - supportingFiles.add(new SupportingFile("application.mustache", resourceFolder, "application.yaml")); + if (additionalProperties.containsKey(GRADLE_BUILD_FILE)) { + this.setGradleBuildFile(Boolean.valueOf(additionalProperties.get(GRADLE_BUILD_FILE).toString())); + } else { + additionalProperties.put(GRADLE_BUILD_FILE, gradleBuildFile); + } modelTemplateFiles.put("model.mustache", ".kt"); apiTemplateFiles.put("api.mustache", ".kt"); @@ -205,7 +217,14 @@ public void processOpts() { if (library.equals(SPRING_BOOT)) { LOGGER.info("Setup code generator for Kotlin Spring Boot"); + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + + if (this.gradleBuildFile) { + supportingFiles.add(new SupportingFile("buildGradleKts.mustache", "", "build.gradle.kts")); + supportingFiles.add(new SupportingFile("settingsGradle.mustache", "", "settings.gradle")); + } + supportingFiles.add(new SupportingFile("application.mustache", resourceFolder, "application.yaml")); supportingFiles.add(new SupportingFile("springBootApplication.mustache", sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache new file mode 100644 index 000000000000..006d2d12ccc8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache @@ -0,0 +1,103 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + 1.2.41 + + + org.springframework.boot + spring-boot-starter-parent + 2.0.3.RELEASE + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + + spring + + 1.8 + + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + org.springframework.boot + spring-boot-starter-web + + + io.swagger + swagger-annotations + 1.5.14 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + +{{#useBeanValidation}} + + + javax.validation + validation-api + +{{/useBeanValidation}} + + diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index 4fec2d09f1bb..0fb9a3c6bb25 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -41,6 +41,7 @@ public void testSettersForConfigValues() throws Exception { codegen.setBasePackage("xx.yyyyyyyy.base"); codegen.setServerPort("8181"); codegen.setExceptionHandler(false); + codegen.setGradleBuildFile(false); codegen.processOpts(); Assert.assertEquals(codegen.modelPackage(), "xx.yyyyyyyy.model"); @@ -53,6 +54,8 @@ public void testSettersForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8181"); Assert.assertFalse(codegen.getExceptionHandler()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); + Assert.assertFalse(codegen.getGradleBuildFile()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.GRADLE_BUILD_FILE), false); } @Test @@ -63,6 +66,7 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { codegen.additionalProperties().put(KotlinSpringServerCodegen.BASE_PACKAGE, "xyz.yyyyy.bbbb.base"); codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVER_PORT, "8088"); codegen.additionalProperties().put(KotlinSpringServerCodegen.EXCEPTION_HANDLER, false); + codegen.additionalProperties().put(KotlinSpringServerCodegen.GRADLE_BUILD_FILE, false); codegen.processOpts(); final OpenAPI openAPI = new OpenAPI(); @@ -79,6 +83,9 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.BASE_PACKAGE), "xyz.yyyyy.bbbb.base"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.TITLE), "someTest"); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8088"); + Assert.assertFalse(codegen.getExceptionHandler()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); + Assert.assertFalse(codegen.getGradleBuildFile()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.GRADLE_BUILD_FILE), false); } } From 9ca036a73dc00d3e100de7780a36aa9339cf048e Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 15 Aug 2018 13:43:10 +0100 Subject: [PATCH 20/39] Fixed up bash scripts for generating test sample code --- .gitignore | 8 +++-- bin/kotlin-springboot-petstore-server.sh | 6 +++- .../kotlin-springboot-petstore-server.sh | 36 +++++++++++++++++++ .../kotlin-springboot-petstore-server.bat | 20 +++++------ .../kotlin-springboot-petstore-server.bat | 10 ++++++ .../languages/KotlinSpringServerCodegen.java | 26 +------------- 6 files changed, 68 insertions(+), 38 deletions(-) create mode 100755 bin/openapi3/kotlin-springboot-petstore-server.sh create mode 100644 bin/windows/openapi3/kotlin-springboot-petstore-server.bat diff --git a/.gitignore b/.gitignore index 55ef266102f2..c7a99f77575f 100644 --- a/.gitignore +++ b/.gitignore @@ -115,14 +115,14 @@ samples/client/petstore/swift/**/SwaggerClientTests/SwaggerClient.xcworkspace/xc samples/client/petstore/swift/**/SwaggerClientTests/Pods/ #samples/client/petstore/swift/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcuserdata #samples/client/petstore/swift/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcshareddata/xcschemes -samples/client/petstore/swift/**/SwaggerClientTests/Podfile.lock +samples/client/petstore/swift/**/SwaggerClientTests/Podfile.lock # Swift3 samples/client/petstore/swift3/**/SwaggerClientTests/SwaggerClient.xcodeproj/xcuserdata samples/client/petstore/swift3/**/SwaggerClientTests/SwaggerClient.xcworkspace/xcuserdata #samples/client/petstore/swift3/**/SwaggerClientTests/Pods/ #samples/client/petstore/swift3/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcuserdata #samples/client/petstore/swift3/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcshareddata/xcschemes -samples/client/petstore/swift3/**/SwaggerClientTests/Podfile.lock +samples/client/petstore/swift3/**/SwaggerClientTests/Podfile.lock # C# *.csproj.user @@ -179,6 +179,10 @@ samples/client/petstore/kotlin-string/build samples/server/petstore/kotlin-server/ktor/build \? +# Kotlin Spring Boot +samples/server/petstore/kotlin-springboot +samples/server/openapi3/petstore/kotlin-springboot + # haskell .stack-work .cabal-sandbox diff --git a/bin/kotlin-springboot-petstore-server.sh b/bin/kotlin-springboot-petstore-server.sh index 4cbb71a26a38..a24fff41a68a 100755 --- a/bin/kotlin-springboot-petstore-server.sh +++ b/bin/kotlin-springboot-petstore-server.sh @@ -27,6 +27,10 @@ fi # if you've executed sbt assembly previously it will use that instead. export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g kotlin-spring -o samples/server/petstore/kotlin-springboot --additional-properties=library=spring-boot" +ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g kotlin-spring -o samples/server/petstore/kotlin-springboot --additional-properties=library=spring-boot" +echo "Cleaning previously generated files if any from samples/server/petstore/kotlin-springboot" +rm -rf samples/server/petstore/kotlin-springboot + +echo "Generating Kotling Spring Boot server..." java $JAVA_OPTS -jar $executable $ags diff --git a/bin/openapi3/kotlin-springboot-petstore-server.sh b/bin/openapi3/kotlin-springboot-petstore-server.sh new file mode 100755 index 000000000000..01331f4f8c64 --- /dev/null +++ b/bin/openapi3/kotlin-springboot-petstore-server.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +SCRIPT="$0" +echo "# START SCRIPT: $SCRIPT" + +while [ -h "$SCRIPT" ] ; do + ls=$(ls -ld "$SCRIPT") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=$(dirname "$SCRIPT")/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=$(dirname "$SCRIPT")/.. + APP_DIR=$(cd "${APP_DIR}"; pwd) +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -g kotlin-spring -o samples/server/openapi3/petstore/kotlin-springboot --additional-properties=library=spring-boot" + +echo "Cleaning previously generated files if any from samples/server/openapi3/petstore/kotlin-springboot" +rm -rf samples/server/openapi3/petstore/kotlin-springboot + +echo "Generating Kotling Spring Boot server..." +java $JAVA_OPTS -jar $executable $ags diff --git a/bin/windows/kotlin-springboot-petstore-server.bat b/bin/windows/kotlin-springboot-petstore-server.bat index 3036b2f56be1..6b7e1ad6e771 100644 --- a/bin/windows/kotlin-springboot-petstore-server.bat +++ b/bin/windows/kotlin-springboot-petstore-server.bat @@ -1,10 +1,10 @@ -set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar - -If Not Exist %executable% ( - mvn clean package -) - -REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties -set ags=generate --artifact-id "kotlin-spring-petstore-server" -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g kotlin-spring -o samples\server\petstore\kotlin-spring - -java %JAVA_OPTS% -jar %executable% %ags% +set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M +set ags=generate -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g kotlin-spring -o samples\server\petstore\kotlin-springboot --additional-properties=library=spring-boot + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/bin/windows/openapi3/kotlin-springboot-petstore-server.bat b/bin/windows/openapi3/kotlin-springboot-petstore-server.bat new file mode 100644 index 000000000000..c86efaee3c81 --- /dev/null +++ b/bin/windows/openapi3/kotlin-springboot-petstore-server.bat @@ -0,0 +1,10 @@ +set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M +set ags=generate -i modules\openapi-generator\src\test\resources\3_0\petstore.yaml -g kotlin-spring -o samples\server\openapi3\petstore\kotlin-springboot --additional-properties=library=spring-boot + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 729e2287028a..a1956bec2299 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -12,27 +12,7 @@ import java.util.*; import java.util.regex.Matcher; -/** - * TODO Config: - * - handle INVOKER_PACKAGE - * - Option to generate services - * - Option to generate service implementations - * - Option to generate default exception handlers - * - Option to generate swagger annotations - * TODO Readme: - * - generate README.md - * TODO Model generation: - * - enable optional bean validation using javax.validation.Valid (currently must be valid) - * TODO Controller generation: - * - Use RestController instead of Controller annotation (see PR #571 for more info) - * TODO General fixes - * - Generated Enum to support Arrays / Maps / Collections - * - Ensure value passed into JsonProperty is a String (see generated SpecialModelname.kt and EnumTest.kt) with escaped $ sign - * - Inheritance - * TODO Other - * - Remove swagger annotations - * - Base types for oneOf (see inheritance) - */ + public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { private static Logger LOGGER = @@ -156,10 +136,6 @@ public void processOpts() { importMapping.put("ToStringSerializer", "com.fasterxml.jackson.databind.ser.std.ToStringSerializer"); importMapping.put("JsonSerialize", "com.fasterxml.jackson.databind.annotation.JsonSerialize"); - // Java import mappings - importMapping.put("Objects", "java.util.Objects"); - importMapping.put("IOException", "java.io.IOException"); - // Swagger import mappings importMapping.put("ApiModel", "io.swagger.annotations.ApiModel"); importMapping.put("ApiModelProperty", "io.swagger.annotations.ApiModelProperty"); From a0ea9e12800dda36905b75cbb583366c7cd6cd90 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 15 Aug 2018 16:39:41 +0100 Subject: [PATCH 21/39] Added configurable option for Swagger Annotations --- .../languages/KotlinSpringServerCodegen.java | 17 +++++++++++++++++ .../main/resources/kotlin-spring/api.mustache | 8 ++++++-- .../resources/kotlin-spring/bodyParams.mustache | 2 +- .../resources/kotlin-spring/formParams.mustache | 2 +- .../kotlin-spring/headerParams.mustache | 2 +- .../spring-boot/buildGradleKts.mustache | 2 ++ .../libraries/spring-boot/pom.mustache | 8 +++++--- .../resources/kotlin-spring/pathParams.mustache | 2 +- .../kotlin-spring/queryParams.mustache | 2 +- .../spring/KotlinSpringServerCodegenTest.java | 6 ++++++ 10 files changed, 41 insertions(+), 10 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index a1956bec2299..32c12ee8ad04 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -31,6 +31,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { public static final String SPRING_BOOT = "spring-boot"; public static final String EXCEPTION_HANDLER = "exceptionHandler"; public static final String GRADLE_BUILD_FILE = "gradleBuildFile"; + public static final String SWAGGER_ANNOTATIONS = "swaggerAnnotations"; private String basePackage; private String serverPort = "8080"; @@ -38,6 +39,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { private String resourceFolder = "src/main/resources"; private boolean exceptionHandler = true; private boolean gradleBuildFile = true; + private boolean swaggerAnnotations = false; public KotlinSpringServerCodegen() { super(); @@ -63,6 +65,7 @@ public KotlinSpringServerCodegen() { addOption(CodegenConstants.API_PACKAGE, "api package for generated code", apiPackage); addSwitch(EXCEPTION_HANDLER, "generate default global exception handlers", exceptionHandler); addSwitch(GRADLE_BUILD_FILE, "generate a gradle build file using the Kotlin DSL", gradleBuildFile); + addSwitch(SWAGGER_ANNOTATIONS, "generate swagger annotations to go alongside controllers and models", swaggerAnnotations); supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); setLibrary(SPRING_BOOT); @@ -113,6 +116,14 @@ public void setGradleBuildFile(boolean gradleBuildFile) { this.gradleBuildFile = gradleBuildFile; } + public boolean getSwaggerAnnotations() { + return this.swaggerAnnotations; + } + + public void setSwaggerAnnotations(boolean swaggerAnnotations) { + this.swaggerAnnotations = swaggerAnnotations; + } + @Override public CodegenType getTag() { return CodegenType.SERVER; @@ -181,6 +192,12 @@ public void processOpts() { additionalProperties.put(GRADLE_BUILD_FILE, gradleBuildFile); } + if (additionalProperties.containsKey(SWAGGER_ANNOTATIONS)) { + this.setSwaggerAnnotations(Boolean.valueOf(additionalProperties.get(SWAGGER_ANNOTATIONS).toString())); + } else { + additionalProperties.put(SWAGGER_ANNOTATIONS, swaggerAnnotations); + } + modelTemplateFiles.put("model.mustache", ".kt"); apiTemplateFiles.put("api.mustache", ".kt"); apiTemplateFiles.put("service.mustache", "Service.kt"); diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index d7d537987c34..0c370ebd529c 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -2,7 +2,8 @@ package {{package}} {{#imports}}import {{import}} {{/imports}} -import io.swagger.annotations.* +{{#swaggerAnnotations}} +import io.swagger.annotations.*{{/swaggerAnnotations}} import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.http.ResponseEntity @@ -22,7 +23,9 @@ import kotlin.collections.List import kotlin.collections.Map @Controller +{{#swaggerAnnotations}} @Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API") +{{/swaggerAnnotations}} {{=<% %>=}} @RequestMapping("\${openapi.<%title%>.base-path:<%>defaultBasePath%>}") <%={{ }}=%> @@ -30,6 +33,7 @@ import kotlin.collections.Map class {{classname}}Controller(@Autowired(required = true) val service: {{classname}}Service) { {{#operation}} + {{#swaggerAnnotations}} @ApiOperation( value = "{{{summary}}}", nickname = "{{{operationId}}}", @@ -38,7 +42,7 @@ class {{classname}}Controller(@Autowired(required = true) val service: {{classna responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = [{{#authMethods}}Authorization(value = "{{name}}"{{#isOAuth}}, scopes = [{{#scopes}}AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, {{/hasMore}}{{/scopes}}]{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}}]{{/hasAuthMethods}}) @ApiResponses( - value = [{{#responses}}ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{baseType}}}::class{{/baseType}}{{#containerType}}, responseContainer = "{{{containerType}}}"{{/containerType}}){{#hasMore}},{{/hasMore}}{{/responses}}]) + value = [{{#responses}}ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{baseType}}}::class{{/baseType}}{{#containerType}}, responseContainer = "{{{containerType}}}"{{/containerType}}){{#hasMore}},{{/hasMore}}{{/responses}}]){{/swaggerAnnotations}} @RequestMapping( value = ["{{{path}}}"],{{#singleContentTypes}}{{#hasProduces}} produces = "{{{vendorExtensions.x-accepts}}}", {{/hasProduces}}{{#hasConsumes}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache index 2a21dd26bb28..041fcb4ccad3 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/bodyParams.mustache @@ -1 +1 @@ -{{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{^isContainer}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{/isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody {{paramName}}: {{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isListContainer}}Mono{{/isListContainer}}{{#isListContainer}}Flux{{/isListContainer}}<{{{baseType}}}>{{/reactive}}{{/isBodyParam}} \ No newline at end of file +{{#isBodyParam}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{^isContainer}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{/isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody {{paramName}}: {{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isListContainer}}Mono{{/isListContainer}}{{#isListContainer}}Flux{{/isListContainer}}<{{{baseType}}}>{{/reactive}}{{/isBodyParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache index 6662feb09854..0b6649b8945a 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/formParams.mustache @@ -1 +1 @@ -{{#isFormParam}}{{^isFile}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{paramName}}: {{{dataType}}} {{/isFile}}{{#isFile}}@ApiParam(value = "file detail") {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart("file") {{baseName}}: MultipartFile{{/isFile}}{{/isFormParam}} \ No newline at end of file +{{#isFormParam}}{{^isFile}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{paramName}}: {{{dataType}}} {{/isFile}}{{#isFile}}{{#swaggerAnnotations}}@ApiParam(value = "file detail"){{/swaggerAnnotations}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart("file") {{baseName}}: MultipartFile{{/isFile}}{{/isFormParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache index 7efa285b62ba..aa702dc4546d 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/headerParams.mustache @@ -1 +1 @@ -{{#isHeaderParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestHeader(value="{{baseName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{paramName}}: {{>optionalDataType}}{{/isHeaderParam}} \ No newline at end of file +{{#isHeaderParam}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} @RequestHeader(value="{{baseName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{paramName}}: {{>optionalDataType}}{{/isHeaderParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache index eb52629b9f45..ad709f4812d8 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache @@ -35,7 +35,9 @@ dependencies { compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") compile("org.jetbrains.kotlin:kotlin-reflect") compile("org.springframework.boot:spring-boot-starter-web") +{{#swaggerAnnotations}} compile("io.swagger:swagger-annotations:1.5.14") +{{/swaggerAnnotations}} testCompile("org.springframework.boot:spring-boot-starter-test") { exclude(module = "junit") diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache index 006d2d12ccc8..7a64ac656f9a 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache @@ -79,11 +79,13 @@ org.springframework.boot spring-boot-starter-web + {{#swaggerAnnotations}} io.swagger swagger-annotations 1.5.14 + {{/swaggerAnnotations}} com.fasterxml.jackson.dataformat jackson-dataformat-yaml @@ -92,12 +94,12 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 -{{#useBeanValidation}} - + {{#useBeanValidation}} + javax.validation validation-api -{{/useBeanValidation}} + {{/useBeanValidation}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache index 243c0eb46e0d..4ab0094b4929 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache @@ -1 +1 @@ -{{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambdaEscapeDoubleQuote}}{{{value}}}{{/lambdaEscapeDoubleQuote}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/enumVars}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathVariable("{{baseName}}") {{paramName}}: {{>optionalDataType}}{{/isPathParam}} \ No newline at end of file +{{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambdaEscapeDoubleQuote}}{{{value}}}{{/lambdaEscapeDoubleQuote}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/enumVars}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} @PathVariable("{{baseName}}") {{paramName}}: {{>optionalDataType}}{{/isPathParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache index e923f135f667..ecceefb0856a 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/queryParams.mustache @@ -1 +1 @@ -{{#isQueryParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}) {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestParam(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{paramName}}: {{>optionalDataType}}{{/isQueryParam}} \ No newline at end of file +{{#isQueryParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}) {{#useBeanValidation}}@Valid{{/useBeanValidation}}{{/swaggerAnnotations}} @RequestParam(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{paramName}}: {{>optionalDataType}}{{/isQueryParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index 0fb9a3c6bb25..ddc7b56f7f5d 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -42,6 +42,7 @@ public void testSettersForConfigValues() throws Exception { codegen.setServerPort("8181"); codegen.setExceptionHandler(false); codegen.setGradleBuildFile(false); + codegen.setSwaggerAnnotations(false); codegen.processOpts(); Assert.assertEquals(codegen.modelPackage(), "xx.yyyyyyyy.model"); @@ -56,6 +57,8 @@ public void testSettersForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); Assert.assertFalse(codegen.getGradleBuildFile()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.GRADLE_BUILD_FILE), false); + Assert.assertFalse(codegen.getSwaggerAnnotations()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS), false); } @Test @@ -67,6 +70,7 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVER_PORT, "8088"); codegen.additionalProperties().put(KotlinSpringServerCodegen.EXCEPTION_HANDLER, false); codegen.additionalProperties().put(KotlinSpringServerCodegen.GRADLE_BUILD_FILE, false); + codegen.additionalProperties().put(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS, false); codegen.processOpts(); final OpenAPI openAPI = new OpenAPI(); @@ -87,5 +91,7 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); Assert.assertFalse(codegen.getGradleBuildFile()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.GRADLE_BUILD_FILE), false); + Assert.assertFalse(codegen.getSwaggerAnnotations()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS), false); } } From 7053851930ab25cc658037eba7912e135392d901 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 15 Aug 2018 17:44:18 +0100 Subject: [PATCH 22/39] Added configurable option for generating service interfaces and service implementations --- .../languages/KotlinSpringServerCodegen.java | 48 ++++++++++++++++++- .../main/resources/kotlin-spring/api.mustache | 4 +- .../kotlin-spring/returnValue.mustache | 1 + .../spring/KotlinSpringServerCodegenTest.java | 24 +++++++--- 4 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/returnValue.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 32c12ee8ad04..f0c75bd99253 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -32,6 +32,8 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { public static final String EXCEPTION_HANDLER = "exceptionHandler"; public static final String GRADLE_BUILD_FILE = "gradleBuildFile"; public static final String SWAGGER_ANNOTATIONS = "swaggerAnnotations"; + public static final String SERVICE_INTERFACE = "serviceInterface"; + public static final String SERVICE_IMPLEMENTATION = "serviceImplementation"; private String basePackage; private String serverPort = "8080"; @@ -40,6 +42,8 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { private boolean exceptionHandler = true; private boolean gradleBuildFile = true; private boolean swaggerAnnotations = false; + private boolean serviceInterface = false; + private boolean serviceImplementation = false; public KotlinSpringServerCodegen() { super(); @@ -66,6 +70,11 @@ public KotlinSpringServerCodegen() { addSwitch(EXCEPTION_HANDLER, "generate default global exception handlers", exceptionHandler); addSwitch(GRADLE_BUILD_FILE, "generate a gradle build file using the Kotlin DSL", gradleBuildFile); addSwitch(SWAGGER_ANNOTATIONS, "generate swagger annotations to go alongside controllers and models", swaggerAnnotations); + addSwitch(SERVICE_INTERFACE, "generate service interfaces to go alongside controllers. In most " + + "cases this option would be used to update an existing project, so not to override implementations. " + + "Useful to help facilitate the generation gap pattern", serviceInterface); + addSwitch(SERVICE_IMPLEMENTATION, "generate stub service implementations that extends service " + + "interfaces. If this is set to true service interfaces will also be generated", serviceImplementation); supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); setLibrary(SPRING_BOOT); @@ -124,6 +133,22 @@ public void setSwaggerAnnotations(boolean swaggerAnnotations) { this.swaggerAnnotations = swaggerAnnotations; } + public boolean getServiceInterface() { + return this.serviceInterface; + } + + public void setServiceInterface(boolean serviceInterface) { + this.serviceInterface = serviceInterface; + } + + public boolean getServiceImplementation() { + return this.serviceImplementation; + } + + public void setServiceImplementation(boolean serviceImplementation) { + this.serviceImplementation = serviceImplementation; + } + @Override public CodegenType getTag() { return CodegenType.SERVER; @@ -198,10 +223,29 @@ public void processOpts() { additionalProperties.put(SWAGGER_ANNOTATIONS, swaggerAnnotations); } + if (additionalProperties.containsKey(SERVICE_INTERFACE)) { + this.setServiceInterface(Boolean.valueOf(additionalProperties.get(SERVICE_INTERFACE).toString())); + } else { + additionalProperties.put(SERVICE_INTERFACE, serviceInterface); + } + + if (additionalProperties.containsKey(SERVICE_IMPLEMENTATION)) { + this.setServiceImplementation(Boolean.valueOf(additionalProperties.get(SERVICE_IMPLEMENTATION).toString())); + } else { + additionalProperties.put(SERVICE_IMPLEMENTATION, serviceImplementation); + } + modelTemplateFiles.put("model.mustache", ".kt"); apiTemplateFiles.put("api.mustache", ".kt"); - apiTemplateFiles.put("service.mustache", "Service.kt"); - apiTemplateFiles.put("serviceImpl.mustache", "ServiceImpl.kt"); + + if (this.serviceInterface) { + apiTemplateFiles.put("service.mustache", "Service.kt"); + } + else if (this.serviceImplementation) { + additionalProperties.put(SERVICE_INTERFACE, true); + apiTemplateFiles.put("service.mustache", "Service.kt"); + apiTemplateFiles.put("serviceImpl.mustache", "ServiceImpl.kt"); + } if (this.exceptionHandler) { supportingFiles.add(new SupportingFile("exceptions.mustache", diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index 0c370ebd529c..33e67ed387b6 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -30,7 +30,7 @@ import kotlin.collections.Map @RequestMapping("\${openapi.<%title%>.base-path:<%>defaultBasePath%>}") <%={{ }}=%> {{#operations}} -class {{classname}}Controller(@Autowired(required = true) val service: {{classname}}Service) { +class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) val service: {{classname}}Service{{/serviceInterface}}) { {{#operation}} {{#swaggerAnnotations}} @@ -51,7 +51,7 @@ class {{classname}}Controller(@Autowired(required = true) val service: {{classna consumes = [{{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}],{{/hasConsumes}}{{/singleContentTypes}} method = [RequestMethod.{{httpMethod}}]) fun {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/allParams}}): ResponseEntity<{{>returnTypes}}> { - return ResponseEntity(service.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}), HttpStatus.OK) + return {{>returnValue}} } {{/operation}} } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/returnValue.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/returnValue.mustache new file mode 100644 index 000000000000..4973c83431d2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/returnValue.mustache @@ -0,0 +1 @@ +{{#serviceInterface}}ResponseEntity(service.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}), HttpStatus.OK){{/serviceInterface}}{{^serviceInterface}}ResponseEntity(HttpStatus.NOT_IMPLEMENTED){{/serviceInterface}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index ddc7b56f7f5d..7c95ef6d3033 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -42,7 +42,9 @@ public void testSettersForConfigValues() throws Exception { codegen.setServerPort("8181"); codegen.setExceptionHandler(false); codegen.setGradleBuildFile(false); - codegen.setSwaggerAnnotations(false); + codegen.setSwaggerAnnotations(true); + codegen.setServiceInterface(true); + codegen.setServiceImplementation(true); codegen.processOpts(); Assert.assertEquals(codegen.modelPackage(), "xx.yyyyyyyy.model"); @@ -57,8 +59,12 @@ public void testSettersForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); Assert.assertFalse(codegen.getGradleBuildFile()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.GRADLE_BUILD_FILE), false); - Assert.assertFalse(codegen.getSwaggerAnnotations()); - Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS), false); + Assert.assertTrue(codegen.getSwaggerAnnotations()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS), true); + Assert.assertTrue(codegen.getServiceInterface()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_INTERFACE), true); + Assert.assertTrue(codegen.getServiceImplementation()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_IMPLEMENTATION), true); } @Test @@ -70,7 +76,9 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVER_PORT, "8088"); codegen.additionalProperties().put(KotlinSpringServerCodegen.EXCEPTION_HANDLER, false); codegen.additionalProperties().put(KotlinSpringServerCodegen.GRADLE_BUILD_FILE, false); - codegen.additionalProperties().put(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS, false); + codegen.additionalProperties().put(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS, true); + codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVICE_INTERFACE, true); + codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVICE_IMPLEMENTATION, true); codegen.processOpts(); final OpenAPI openAPI = new OpenAPI(); @@ -91,7 +99,11 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.EXCEPTION_HANDLER), false); Assert.assertFalse(codegen.getGradleBuildFile()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.GRADLE_BUILD_FILE), false); - Assert.assertFalse(codegen.getSwaggerAnnotations()); - Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS), false); + Assert.assertTrue(codegen.getSwaggerAnnotations()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS), true); + Assert.assertTrue(codegen.getServiceInterface()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_INTERFACE), true); + Assert.assertTrue(codegen.getServiceImplementation()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_IMPLEMENTATION), true); } } From 2edf44b23790d83328219c4657309d74aa7764a5 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 15 Aug 2018 18:04:29 +0100 Subject: [PATCH 23/39] Added README generation --- .../languages/KotlinSpringServerCodegen.java | 1 + .../libraries/spring-boot/README.mustache | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index f0c75bd99253..cd2a051a25d1 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -237,6 +237,7 @@ public void processOpts() { modelTemplateFiles.put("model.mustache", ".kt"); apiTemplateFiles.put("api.mustache", ".kt"); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); if (this.serviceInterface) { apiTemplateFiles.put("service.mustache", "Service.kt"); diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache new file mode 100644 index 000000000000..736509fe212b --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache @@ -0,0 +1,21 @@ +# {{#title}}{{title}}{{/title}}{{^title}}Generated Kotlin Spring Boot App{{/title}} + +This Kotlin based [Spring Boot](https://spring.io/projects/spring-boot) application has been generated using the [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator). + +## Getting Started + +This document assumes you have either maven or gradle available, either via the wrapper or otherwise. This does not come with a gradle / maven wrapper checked in. + +By default a [`pom.xml`](pom.xml) file will be generated. If you specified `gradleBuildFile=true` when generating this project, a `build.gradle.kts` will also be generated. Note this uses [Gradle Kotlin DSL](https://github.com/gradle/kotlin-dsl). + +To build the project using maven, run: +```bash +mvn package && java -jar target/openapi-spring-1.0.0.jar +``` + +To build the project using gradle, run: +```bash +gradle build && java -jar build/libs/openapi-spring-1.0.0.jar +``` + +If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:8080/) From 92326f9785b01b53ae49fc1a8e5f6397676f96c5 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Thu, 16 Aug 2018 18:02:59 +0100 Subject: [PATCH 24/39] Enable optional bean validation --- .../languages/AbstractKotlinCodegen.java | 5 +++ .../languages/KotlinSpringServerCodegen.java | 38 ++++++++++++------- .../main/resources/kotlin-spring/api.mustache | 14 ++++++- .../beanValidationModel.mustache | 20 ++++++++++ .../kotlin-spring/beanValidationPath.mustache | 20 ++++++++++ .../beanValidationPathParams.mustache | 1 + .../beanValidationQueryParams.mustache | 1 + .../kotlin-spring/dataClassOptVar.mustache | 8 ++-- .../kotlin-spring/dataClassReqVar.mustache | 8 ++-- .../resources/kotlin-spring/model.mustache | 5 +++ .../spring/KotlinSpringServerCodegenTest.java | 6 +++ 11 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationModel.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPath.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPathParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index 0d3907aa31c8..c7d03133fa3b 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -666,6 +666,11 @@ public String toVarName(String name) { return name; } + @Override + public String toRegularExpression(String pattern) { + return escapeText(pattern); + } + private boolean startsWithTwoUppercaseLetters(String name) { boolean startsWithTwoUppercaseLetters = false; if (name.length() > 1) { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index cd2a051a25d1..4865afd9e0d6 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -3,6 +3,7 @@ import com.samskivert.mustache.Mustache; import io.swagger.v3.oas.models.OpenAPI; import org.openapitools.codegen.*; +import org.openapitools.codegen.languages.features.BeanValidationFeatures; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,7 +14,8 @@ import java.util.regex.Matcher; -public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { +public class KotlinSpringServerCodegen extends AbstractKotlinCodegen + implements BeanValidationFeatures { private static Logger LOGGER = LoggerFactory.getLogger(KotlinSpringServerCodegen.class); @@ -39,6 +41,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen { private String serverPort = "8080"; private String title = "OpenAPI Kotlin Spring"; private String resourceFolder = "src/main/resources"; + private boolean useBeanValidation = true; private boolean exceptionHandler = true; private boolean gradleBuildFile = true; private boolean swaggerAnnotations = false; @@ -75,6 +78,7 @@ public KotlinSpringServerCodegen() { "Useful to help facilitate the generation gap pattern", serviceInterface); addSwitch(SERVICE_IMPLEMENTATION, "generate stub service implementations that extends service " + "interfaces. If this is set to true service interfaces will also be generated", serviceImplementation); + addSwitch(USE_BEANVALIDATION, "Use BeanValidation API annotations to validate data types", useBeanValidation); supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); setLibrary(SPRING_BOOT); @@ -149,6 +153,15 @@ public void setServiceImplementation(boolean serviceImplementation) { this.serviceImplementation = serviceImplementation; } + public boolean getUseBeanValidation() { + return this.useBeanValidation; + } + + @Override + public void setUseBeanValidation(boolean useBeanValidation) { + this.useBeanValidation = useBeanValidation; + } + @Override public CodegenType getTag() { return CodegenType.SERVER; @@ -207,33 +220,33 @@ public void processOpts() { if (additionalProperties.containsKey(EXCEPTION_HANDLER)) { this.setExceptionHandler(Boolean.valueOf(additionalProperties.get(EXCEPTION_HANDLER).toString())); - } else { - additionalProperties.put(EXCEPTION_HANDLER, exceptionHandler); } + writePropertyBack(EXCEPTION_HANDLER, exceptionHandler); if (additionalProperties.containsKey(GRADLE_BUILD_FILE)) { this.setGradleBuildFile(Boolean.valueOf(additionalProperties.get(GRADLE_BUILD_FILE).toString())); - } else { - additionalProperties.put(GRADLE_BUILD_FILE, gradleBuildFile); } + writePropertyBack(GRADLE_BUILD_FILE, gradleBuildFile); if (additionalProperties.containsKey(SWAGGER_ANNOTATIONS)) { this.setSwaggerAnnotations(Boolean.valueOf(additionalProperties.get(SWAGGER_ANNOTATIONS).toString())); - } else { - additionalProperties.put(SWAGGER_ANNOTATIONS, swaggerAnnotations); } + writePropertyBack(SWAGGER_ANNOTATIONS, swaggerAnnotations); if (additionalProperties.containsKey(SERVICE_INTERFACE)) { this.setServiceInterface(Boolean.valueOf(additionalProperties.get(SERVICE_INTERFACE).toString())); - } else { - additionalProperties.put(SERVICE_INTERFACE, serviceInterface); } + writePropertyBack(SERVICE_INTERFACE, serviceInterface); if (additionalProperties.containsKey(SERVICE_IMPLEMENTATION)) { this.setServiceImplementation(Boolean.valueOf(additionalProperties.get(SERVICE_IMPLEMENTATION).toString())); - } else { - additionalProperties.put(SERVICE_IMPLEMENTATION, serviceImplementation); } + writePropertyBack(SERVICE_IMPLEMENTATION, serviceImplementation); + + if (additionalProperties.containsKey(USE_BEANVALIDATION)) { + this.setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION)); + } + writePropertyBack(USE_BEANVALIDATION, useBeanValidation); modelTemplateFiles.put("model.mustache", ".kt"); apiTemplateFiles.put("api.mustache", ".kt"); @@ -241,8 +254,7 @@ public void processOpts() { if (this.serviceInterface) { apiTemplateFiles.put("service.mustache", "Service.kt"); - } - else if (this.serviceImplementation) { + } else if (this.serviceImplementation) { additionalProperties.put(SERVICE_INTERFACE, true); apiTemplateFiles.put("service.mustache", "Service.kt"); apiTemplateFiles.put("serviceImpl.mustache", "ServiceImpl.kt"); diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index 33e67ed387b6..2ea2299c0f67 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -3,7 +3,8 @@ package {{package}} {{#imports}}import {{import}} {{/imports}} {{#swaggerAnnotations}} -import io.swagger.annotations.*{{/swaggerAnnotations}} +import io.swagger.annotations.* +{{/swaggerAnnotations}} import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.http.ResponseEntity @@ -15,14 +16,25 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping +{{#useBeanValidation}} +import org.springframework.validation.annotation.Validated +{{/useBeanValidation}} import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile import org.springframework.beans.factory.annotation.Autowired +{{#useBeanValidation}} +import javax.validation.Valid +import javax.validation.constraints.* +{{/useBeanValidation}} + import kotlin.collections.List import kotlin.collections.Map @Controller +{{#useBeanValidation}} +@Validated +{{/useBeanValidation}} {{#swaggerAnnotations}} @Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API") {{/swaggerAnnotations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationModel.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationModel.mustache new file mode 100644 index 000000000000..0564f1e3630f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationModel.mustache @@ -0,0 +1,20 @@ +{{#pattern}}@get:Pattern(regexp="{{{pattern}}}") {{/pattern}}{{! +minLength && maxLength set +}}{{#minLength}}{{#maxLength}}@get:Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +minLength set, maxLength not +}}{{#minLength}}{{^maxLength}}@get:Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{! +minLength not set, maxLength set +}}{{^minLength}}{{#maxLength}}@get:Size(max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +@Size: minItems && maxItems set +}}{{#minItems}}{{#maxItems}}@get:Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems set, maxItems not +}}{{#minItems}}{{^maxItems}}@get:Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems not set && maxItems set +}}{{^minItems}}{{#maxItems}}@get:Size(max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +check for integer or long / all others=decimal type with @Decimal* +isInteger set +}}{{#isInteger}}{{#minimum}}@get:Min({{minimum}}){{/minimum}}{{#maximum}} @get:Max({{maximum}}) {{/maximum}}{{/isInteger}}{{! +isLong set +}}{{#isLong}}{{#minimum}}@get:Min({{minimum}}L){{/minimum}}{{#maximum}} @get:Max({{maximum}}L) {{/maximum}}{{/isLong}}{{! +Not Integer, not Long => we have a decimal value! +}}{{^isInteger}}{{^isLong}}{{#minimum}}@get:DecimalMin("{{minimum}}"){{/minimum}}{{#maximum}} @get:DecimalMax("{{maximum}}") {{/maximum}}{{/isLong}}{{/isInteger}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPath.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPath.mustache new file mode 100644 index 000000000000..4b7b561ce708 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPath.mustache @@ -0,0 +1,20 @@ +{{#pattern}}@Pattern(regexp="{{{pattern}}}") {{/pattern}}{{! +minLength && maxLength set +}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +minLength set, maxLength not +}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{! +minLength not set, maxLength set +}}{{^minLength}}{{#maxLength}}@Size(max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +@Size: minItems && maxItems set +}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems set, maxItems not +}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems not set && maxItems set +}}{{^minItems}}{{#maxItems}}@Size(max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +check for integer or long / all others=decimal type with @Decimal* +isInteger set +}}{{#isInteger}}{{#minimum}}@Min({{minimum}}){{/minimum}}{{#maximum}} @Max({{maximum}}) {{/maximum}}{{/isInteger}}{{! +isLong set +}}{{#isLong}}{{#minimum}}@Min({{minimum}}L){{/minimum}}{{#maximum}} @Max({{maximum}}L) {{/maximum}}{{/isLong}}{{! +Not Integer, not Long => we have a decimal value! +}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin("{{minimum}}"){{/minimum}}{{#maximum}} @DecimalMax("{{maximum}}") {{/maximum}}{{/isLong}}{{/isInteger}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPathParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPathParams.mustache new file mode 100644 index 000000000000..3c57e76be1ad --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationPathParams.mustache @@ -0,0 +1 @@ +{{! PathParam is always required, no @NotNull necessary }}{{>beanValidationPath}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache new file mode 100644 index 000000000000..9cca8cb88748 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache @@ -0,0 +1 @@ +{{#required}}@NotNull {{/required}}{{>beanValidationCore}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache index b87ec9680348..52b6ae1157da 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache @@ -1,4 +1,4 @@ -{{#description}} - /* {{{description}}} */ -{{/description}} - @JsonProperty("{{{baseName}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file +{{#useBeanValidation}}{{#required}} + @get:NotNull {{/required}}{{>beanValidationModel}}{{/useBeanValidation}}{{#swaggerAnnotations}} + @ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swaggerAnnotations}} + @JsonProperty("{{{baseName}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache index 2a6cb7bb7004..e09ea971bead 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache @@ -1,4 +1,4 @@ -{{#description}} - /* {{{description}}} */ -{{/description}} - @JsonProperty("{{{baseName}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}} \ No newline at end of file +{{#useBeanValidation}}{{#required}} + @get:NotNull {{/required}}{{>beanValidationModel}}{{/useBeanValidation}}{{#swaggerAnnotations}} + @ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swaggerAnnotations}} + @JsonProperty("{{{baseName}}}") val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache index 5335b9c0caaa..37e21201cffc 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/model.mustache @@ -3,8 +3,13 @@ package {{package}} import java.util.Objects {{#imports}}import {{import}} {{/imports}} +{{#useBeanValidation}} import javax.validation.Valid import javax.validation.constraints.* +{{/useBeanValidation}} +{{#swaggerAnnotations}} +import io.swagger.annotations.ApiModelProperty +{{/swaggerAnnotations}} {{#models}} {{#model}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index 7c95ef6d3033..17ec8e74c205 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -45,6 +45,7 @@ public void testSettersForConfigValues() throws Exception { codegen.setSwaggerAnnotations(true); codegen.setServiceInterface(true); codegen.setServiceImplementation(true); + codegen.setUseBeanValidation(false); codegen.processOpts(); Assert.assertEquals(codegen.modelPackage(), "xx.yyyyyyyy.model"); @@ -65,6 +66,8 @@ public void testSettersForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_INTERFACE), true); Assert.assertTrue(codegen.getServiceImplementation()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_IMPLEMENTATION), true); + Assert.assertFalse(codegen.getUseBeanValidation()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.USE_BEANVALIDATION), false); } @Test @@ -79,6 +82,7 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { codegen.additionalProperties().put(KotlinSpringServerCodegen.SWAGGER_ANNOTATIONS, true); codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVICE_INTERFACE, true); codegen.additionalProperties().put(KotlinSpringServerCodegen.SERVICE_IMPLEMENTATION, true); + codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_BEANVALIDATION, false); codegen.processOpts(); final OpenAPI openAPI = new OpenAPI(); @@ -105,5 +109,7 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_INTERFACE), true); Assert.assertTrue(codegen.getServiceImplementation()); Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVICE_IMPLEMENTATION), true); + Assert.assertFalse(codegen.getUseBeanValidation()); + Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.USE_BEANVALIDATION), false); } } From b9f8c5b4e3db221af216f86dbb7bfbb2e8ee6a1b Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Thu, 16 Aug 2018 18:10:01 +0100 Subject: [PATCH 25/39] Added kotlin spring sample to CircleCI pom.xml --- CI/pom.xml.circleci | 1 + 1 file changed, 1 insertion(+) diff --git a/CI/pom.xml.circleci b/CI/pom.xml.circleci index bf2d5323a0a3..1d50c1410d89 100644 --- a/CI/pom.xml.circleci +++ b/CI/pom.xml.circleci @@ -957,6 +957,7 @@ samples/server/petstore/scala-lagom-server samples/server/petstore/scalatra samples/server/petstore/finch + samples/server/petstore/kotlin-springboot From 31195851e0212ec5c3b91f575f563d0ac7489a5f Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Mon, 20 Aug 2018 11:42:31 +0100 Subject: [PATCH 26/39] Removed kotlin spring boot from .gitignore --- .gitignore | 4 - .../.openapi-generator-ignore | 23 +++ .../.openapi-generator/VERSION | 1 + .../kotlin-springboot/build.gradle.kts | 43 +++++ .../petstore/kotlin-springboot/pom.xml | 96 +++++++++++ .../kotlin-springboot/settings.gradle | 1 + .../kotlin/org/openapitools/Application.kt | 14 ++ .../kotlin/org/openapitools/api/Exceptions.kt | 24 +++ .../kotlin/org/openapitools/api/PetApi.kt | 154 ++++++++++++++++++ .../org/openapitools/api/PetApiService.kt | 23 +++ .../org/openapitools/api/PetApiServiceImpl.kt | 41 +++++ .../kotlin/org/openapitools/api/StoreApi.kt | 88 ++++++++++ .../org/openapitools/api/StoreApiService.kt | 14 ++ .../openapitools/api/StoreApiServiceImpl.kt | 24 +++ .../kotlin/org/openapitools/api/UserApi.kt | 139 ++++++++++++++++ .../org/openapitools/api/UserApiService.kt | 22 +++ .../openapitools/api/UserApiServiceImpl.kt | 40 +++++ .../kotlin/org/openapitools/model/Category.kt | 19 +++ .../openapitools/model/ModelApiResponse.kt | 21 +++ .../kotlin/org/openapitools/model/Order.kt | 43 +++++ .../main/kotlin/org/openapitools/model/Pet.kt | 45 +++++ .../main/kotlin/org/openapitools/model/Tag.kt | 19 +++ .../kotlin/org/openapitools/model/User.kt | 32 ++++ .../src/main/resources/application.yaml | 3 + .../.openapi-generator-ignore | 23 +++ .../.openapi-generator/VERSION | 1 + .../kotlin-springboot/build.gradle.kts | 43 +++++ .../server/petstore/kotlin-springboot/pom.xml | 96 +++++++++++ .../kotlin-springboot/settings.gradle | 1 + .../kotlin/org/openapitools/Application.kt | 14 ++ .../kotlin/org/openapitools/api/Exceptions.kt | 24 +++ .../kotlin/org/openapitools/api/PetApi.kt | 154 ++++++++++++++++++ .../org/openapitools/api/PetApiService.kt | 23 +++ .../org/openapitools/api/PetApiServiceImpl.kt | 41 +++++ .../kotlin/org/openapitools/api/StoreApi.kt | 87 ++++++++++ .../org/openapitools/api/StoreApiService.kt | 14 ++ .../openapitools/api/StoreApiServiceImpl.kt | 24 +++ .../kotlin/org/openapitools/api/UserApi.kt | 135 +++++++++++++++ .../org/openapitools/api/UserApiService.kt | 22 +++ .../openapitools/api/UserApiServiceImpl.kt | 40 +++++ .../kotlin/org/openapitools/model/Category.kt | 19 +++ .../openapitools/model/ModelApiResponse.kt | 21 +++ .../kotlin/org/openapitools/model/Order.kt | 43 +++++ .../main/kotlin/org/openapitools/model/Pet.kt | 45 +++++ .../main/kotlin/org/openapitools/model/Tag.kt | 19 +++ .../kotlin/org/openapitools/model/User.kt | 32 ++++ .../src/main/resources/application.yaml | 3 + 47 files changed, 1853 insertions(+), 4 deletions(-) create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator-ignore create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/pom.xml create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/settings.gradle create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/resources/application.yaml create mode 100644 samples/server/petstore/kotlin-springboot/.openapi-generator-ignore create mode 100644 samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION create mode 100644 samples/server/petstore/kotlin-springboot/build.gradle.kts create mode 100644 samples/server/petstore/kotlin-springboot/pom.xml create mode 100644 samples/server/petstore/kotlin-springboot/settings.gradle create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt create mode 100644 samples/server/petstore/kotlin-springboot/src/main/resources/application.yaml diff --git a/.gitignore b/.gitignore index c7a99f77575f..9fd7f8b7a6f3 100644 --- a/.gitignore +++ b/.gitignore @@ -179,10 +179,6 @@ samples/client/petstore/kotlin-string/build samples/server/petstore/kotlin-server/ktor/build \? -# Kotlin Spring Boot -samples/server/petstore/kotlin-springboot -samples/server/openapi3/petstore/kotlin-springboot - # haskell .stack-work .cabal-sandbox diff --git a/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator-ignore b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION new file mode 100644 index 000000000000..105bb87d77b3 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION @@ -0,0 +1 @@ +3.2.2-SNAPSHOT \ No newline at end of file diff --git a/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts b/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts new file mode 100644 index 000000000000..79962e285bbf --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts @@ -0,0 +1,43 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +buildscript { + repositories { + jcenter() + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE") + } +} + +group = "org.openapitools" +version = "1.0.0" + +repositories { + jcenter() + mavenCentral() +} + +tasks.withType { + kotlinOptions.jvmTarget = "1.8" +} + +plugins { + val kotlinVersion = "1.2.41" + id("org.jetbrains.kotlin.jvm") version kotlinVersion + id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion + id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion + id("org.springframework.boot") version "2.0.3.RELEASE" + id("io.spring.dependency-management") version "1.0.5.RELEASE" +} + +dependencies { + compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + compile("org.jetbrains.kotlin:kotlin-reflect") + compile("org.springframework.boot:spring-boot-starter-web") + compile("io.swagger:swagger-annotations:1.5.14") + + testCompile("org.springframework.boot:spring-boot-starter-test") { + exclude(module = "junit") + } +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/pom.xml b/samples/server/openapi3/petstore/kotlin-springboot/pom.xml new file mode 100644 index 000000000000..0b29122357e7 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/pom.xml @@ -0,0 +1,96 @@ + + 4.0.0 + org.openapitools + openapi-spring + jar + openapi-spring + 1.0.0 + + 1.2.41 + + + org.springframework.boot + spring-boot-starter-parent + 2.0.3.RELEASE + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + + spring + + 1.8 + + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + org.springframework.boot + spring-boot-starter-web + + + io.swagger + swagger-annotations + 1.5.14 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/settings.gradle b/samples/server/openapi3/petstore/kotlin-springboot/settings.gradle new file mode 100644 index 000000000000..f0dd035311e0 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "openapi-spring" \ No newline at end of file diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt new file mode 100644 index 000000000000..f2ee49d476b6 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt @@ -0,0 +1,14 @@ +package org.openapitools + +import org.springframework.boot.runApplication +import org.springframework.context.annotation.ComponentScan +import org.springframework.boot.autoconfigure.SpringBootApplication + + +@SpringBootApplication +@ComponentScan(basePackages = ["org.openapitools", "org.openapitools.api", "org.openapitools.model"]) +class Application + +fun main(args: Array) { + runApplication(*args) +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt new file mode 100644 index 000000000000..afba2986af28 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -0,0 +1,24 @@ +package org.openapitools.api + +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ControllerAdvice +import org.springframework.web.bind.annotation.ExceptionHandler +import javax.servlet.http.HttpServletRequest + +sealed class ApiException(msg: String, val code: Int) : Exception(msg) + +class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) + + +@ControllerAdvice +class DefaultExceptionHandler { + + @ExceptionHandler(value = [NotFoundException::class]) + fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.valueOf(ex.code)) + + @ExceptionHandler(value = [NotImplementedError::class]) + fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.NOT_IMPLEMENTED) +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt new file mode 100644 index 000000000000..d7e2a4729324 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -0,0 +1,154 @@ +package org.openapitools.api + +import org.openapitools.model.ModelApiResponse +import org.openapitools.model.Pet +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile +import org.springframework.beans.factory.annotation.Autowired + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +@Api(value = "Pet", description = "The Pet API") +@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") +class PetApiController(@Autowired(required = true) val service: PetApiService) { + + @ApiOperation( + value = "Add a new pet to the store", + nickname = "addPet", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 405, message = "Invalid input")]) + @RequestMapping( + value = ["/pet"], + consumes = ["application/json", "application/xml"], + method = [RequestMethod.POST]) + fun addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + return ResponseEntity(service.addPet(pet), HttpStatus.OK) + } + + @ApiOperation( + value = "Deletes a pet", + nickname = "deletePet", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid pet value")]) + @RequestMapping( + value = ["/pet/{petId}"], + method = [RequestMethod.DELETE]) + fun deletePet(@ApiParam(value = "Pet id to delete", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "" ) @RequestHeader(value="api_key", required=false) apiKey: kotlin.String): ResponseEntity { + return ResponseEntity(service.deletePet(petId, apiKey), HttpStatus.OK) + } + + @ApiOperation( + value = "Finds Pets by status", + nickname = "findPetsByStatus", + notes = "Multiple status values can be provided with comma separated strings", + response = Pet::class, + responseContainer = "List", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid status value")]) + @RequestMapping( + value = ["/pet/findByStatus"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun findPetsByStatus(@ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @RequestParam(value = "status", required = true) status: kotlin.Array): ResponseEntity> { + return ResponseEntity(service.findPetsByStatus(status), HttpStatus.OK) + } + + @ApiOperation( + value = "Finds Pets by tags", + nickname = "findPetsByTags", + notes = "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + response = Pet::class, + responseContainer = "List", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid tag value")]) + @RequestMapping( + value = ["/pet/findByTags"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun findPetsByTags(@ApiParam(value = "Tags to filter by", required = true) @RequestParam(value = "tags", required = true) tags: kotlin.Array): ResponseEntity> { + return ResponseEntity(service.findPetsByTags(tags), HttpStatus.OK) + } + + @ApiOperation( + value = "Find pet by ID", + nickname = "getPetById", + notes = "Returns a single pet", + response = Pet::class, + authorizations = [Authorization(value = "api_key")]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Pet not found")]) + @RequestMapping( + value = ["/pet/{petId}"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun getPetById(@ApiParam(value = "ID of pet to return", required=true) @PathVariable("petId") petId: kotlin.Long): ResponseEntity { + return ResponseEntity(service.getPetById(petId), HttpStatus.OK) + } + + @ApiOperation( + value = "Update an existing pet", + nickname = "updatePet", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Pet not found"),ApiResponse(code = 405, message = "Validation exception")]) + @RequestMapping( + value = ["/pet"], + consumes = ["application/json", "application/xml"], + method = [RequestMethod.PUT]) + fun updatePet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + return ResponseEntity(service.updatePet(pet), HttpStatus.OK) + } + + @ApiOperation( + value = "Updates a pet in the store with form data", + nickname = "updatePetWithForm", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 405, message = "Invalid input")]) + @RequestMapping( + value = ["/pet/{petId}"], + consumes = ["application/x-www-form-urlencoded"], + method = [RequestMethod.POST]) + fun updatePetWithForm(@ApiParam(value = "ID of pet that needs to be updated", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Updated name of the pet", defaultValue="null") @RequestParam(value="name", required=false) name: kotlin.String ,@ApiParam(value = "Updated status of the pet", defaultValue="null") @RequestParam(value="status", required=false) status: kotlin.String ): ResponseEntity { + return ResponseEntity(service.updatePetWithForm(petId, name, status), HttpStatus.OK) + } + + @ApiOperation( + value = "uploads an image", + nickname = "uploadFile", + notes = "", + response = ModelApiResponse::class, + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = ModelApiResponse::class)]) + @RequestMapping( + value = ["/pet/{petId}/uploadImage"], + produces = ["application/json"], + consumes = ["multipart/form-data"], + method = [RequestMethod.POST]) + fun uploadFile(@ApiParam(value = "ID of pet to update", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Additional data to pass to server", defaultValue="null") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: kotlin.String ,@ApiParam(value = "file detail") @RequestPart("file") file: MultipartFile): ResponseEntity { + return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK) + } +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt new file mode 100644 index 000000000000..e7bd7fae34ef --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt @@ -0,0 +1,23 @@ +package org.openapitools.api + +import org.openapitools.model.ModelApiResponse +import org.openapitools.model.Pet + +interface PetApiService { + + fun addPet(pet: Pet): Unit + + fun deletePet(petId: kotlin.Long,apiKey: kotlin.String): Unit + + fun findPetsByStatus(status: kotlin.Array): List + + fun findPetsByTags(tags: kotlin.Array): List + + fun getPetById(petId: kotlin.Long): Pet + + fun updatePet(pet: Pet): Unit + + fun updatePetWithForm(petId: kotlin.Long,name: kotlin.String,status: kotlin.String): Unit + + fun uploadFile(petId: kotlin.Long,additionalMetadata: kotlin.String,file: org.springframework.web.multipart.MultipartFile): ModelApiResponse +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt new file mode 100644 index 000000000000..e898ab98921b --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt @@ -0,0 +1,41 @@ +package org.openapitools.api + +import org.openapitools.model.ModelApiResponse +import org.openapitools.model.Pet +import org.springframework.stereotype.Service + +@Service +class PetApiServiceImpl : PetApiService { + + override fun addPet(pet: Pet): Unit { + TODO("Implement me") + } + + override fun deletePet(petId: kotlin.Long,apiKey: kotlin.String): Unit { + TODO("Implement me") + } + + override fun findPetsByStatus(status: kotlin.Array): List { + TODO("Implement me") + } + + override fun findPetsByTags(tags: kotlin.Array): List { + TODO("Implement me") + } + + override fun getPetById(petId: kotlin.Long): Pet { + TODO("Implement me") + } + + override fun updatePet(pet: Pet): Unit { + TODO("Implement me") + } + + override fun updatePetWithForm(petId: kotlin.Long,name: kotlin.String,status: kotlin.String): Unit { + TODO("Implement me") + } + + override fun uploadFile(petId: kotlin.Long,additionalMetadata: kotlin.String,file: org.springframework.web.multipart.MultipartFile): ModelApiResponse { + TODO("Implement me") + } +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt new file mode 100644 index 000000000000..7c272813412f --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt @@ -0,0 +1,88 @@ +package org.openapitools.api + +import org.openapitools.model.Order +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile +import org.springframework.beans.factory.annotation.Autowired + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +@Api(value = "Store", description = "The Store API") +@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") +class StoreApiController(@Autowired(required = true) val service: StoreApiService) { + + @ApiOperation( + value = "Delete purchase order by ID", + nickname = "deleteOrder", + notes = "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors") + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Order not found")]) + @RequestMapping( + value = ["/store/order/{orderId}"], + method = [RequestMethod.DELETE]) + fun deleteOrder(@ApiParam(value = "ID of the order that needs to be deleted", required=true) @PathVariable("orderId") orderId: kotlin.String): ResponseEntity { + return ResponseEntity(service.deleteOrder(orderId), HttpStatus.OK) + } + + @ApiOperation( + value = "Returns pet inventories by status", + nickname = "getInventory", + notes = "Returns a map of status codes to quantities", + response = kotlin.Int::class, + responseContainer = "Map", + authorizations = [Authorization(value = "api_key")]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = kotlin.collections.Map::class, responseContainer = "Map")]) + @RequestMapping( + value = ["/store/inventory"], + produces = ["application/json"], + method = [RequestMethod.GET]) + fun getInventory(): ResponseEntity> { + return ResponseEntity(service.getInventory(), HttpStatus.OK) + } + + @ApiOperation( + value = "Find purchase order by ID", + nickname = "getOrderById", + notes = "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions", + response = Order::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Order not found")]) + @RequestMapping( + value = ["/store/order/{orderId}"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun getOrderById(@ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity { + return ResponseEntity(service.getOrderById(orderId), HttpStatus.OK) + } + + @ApiOperation( + value = "Place an order for a pet", + nickname = "placeOrder", + notes = "", + response = Order::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid Order")]) + @RequestMapping( + value = ["/store/order"], + produces = ["application/xml", "application/json"], + consumes = ["application/json"], + method = [RequestMethod.POST]) + fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @RequestBody order: Order): ResponseEntity { + return ResponseEntity(service.placeOrder(order), HttpStatus.OK) + } +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt new file mode 100644 index 000000000000..5eb379cb1854 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt @@ -0,0 +1,14 @@ +package org.openapitools.api + +import org.openapitools.model.Order + +interface StoreApiService { + + fun deleteOrder(orderId: kotlin.String): Unit + + fun getInventory(): Map + + fun getOrderById(orderId: kotlin.Long): Order + + fun placeOrder(order: Order): Order +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt new file mode 100644 index 000000000000..87d2551740d3 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt @@ -0,0 +1,24 @@ +package org.openapitools.api + +import org.openapitools.model.Order +import org.springframework.stereotype.Service + +@Service +class StoreApiServiceImpl : StoreApiService { + + override fun deleteOrder(orderId: kotlin.String): Unit { + TODO("Implement me") + } + + override fun getInventory(): Map { + TODO("Implement me") + } + + override fun getOrderById(orderId: kotlin.Long): Order { + TODO("Implement me") + } + + override fun placeOrder(order: Order): Order { + TODO("Implement me") + } +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt new file mode 100644 index 000000000000..feb69360819a --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt @@ -0,0 +1,139 @@ +package org.openapitools.api + +import org.openapitools.model.User +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile +import org.springframework.beans.factory.annotation.Autowired + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +@Api(value = "User", description = "The User API") +@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") +class UserApiController(@Autowired(required = true) val service: UserApiService) { + + @ApiOperation( + value = "Create user", + nickname = "createUser", + notes = "This can only be done by the logged in user.") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user"], + consumes = ["application/json"], + method = [RequestMethod.POST]) + fun createUser(@ApiParam(value = "Created user object" ,required=true ) @RequestBody user: User): ResponseEntity { + return ResponseEntity(service.createUser(user), HttpStatus.OK) + } + + @ApiOperation( + value = "Creates list of users with given input array", + nickname = "createUsersWithArrayInput", + notes = "") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user/createWithArray"], + consumes = ["application/json"], + method = [RequestMethod.POST]) + fun createUsersWithArrayInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + return ResponseEntity(service.createUsersWithArrayInput(user), HttpStatus.OK) + } + + @ApiOperation( + value = "Creates list of users with given input array", + nickname = "createUsersWithListInput", + notes = "") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user/createWithList"], + consumes = ["application/json"], + method = [RequestMethod.POST]) + fun createUsersWithListInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + return ResponseEntity(service.createUsersWithListInput(user), HttpStatus.OK) + } + + @ApiOperation( + value = "Delete user", + nickname = "deleteUser", + notes = "This can only be done by the logged in user.") + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid username supplied"),ApiResponse(code = 404, message = "User not found")]) + @RequestMapping( + value = ["/user/{username}"], + method = [RequestMethod.DELETE]) + fun deleteUser(@ApiParam(value = "The name that needs to be deleted", required=true) @PathVariable("username") username: kotlin.String): ResponseEntity { + return ResponseEntity(service.deleteUser(username), HttpStatus.OK) + } + + @ApiOperation( + value = "Get user by user name", + nickname = "getUserByName", + notes = "", + response = User::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = User::class),ApiResponse(code = 400, message = "Invalid username supplied"),ApiResponse(code = 404, message = "User not found")]) + @RequestMapping( + value = ["/user/{username}"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun getUserByName(@ApiParam(value = "The name that needs to be fetched. Use user1 for testing.", required=true) @PathVariable("username") username: kotlin.String): ResponseEntity { + return ResponseEntity(service.getUserByName(username), HttpStatus.OK) + } + + @ApiOperation( + value = "Logs user into the system", + nickname = "loginUser", + notes = "", + response = kotlin.String::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = kotlin.String::class),ApiResponse(code = 400, message = "Invalid username/password supplied")]) + @RequestMapping( + value = ["/user/login"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun loginUser(@ApiParam(value = "The user name for login", required = true) @RequestParam(value = "username", required = true) username: kotlin.String,@ApiParam(value = "The password for login in clear text", required = true) @RequestParam(value = "password", required = true) password: kotlin.String): ResponseEntity { + return ResponseEntity(service.loginUser(username, password), HttpStatus.OK) + } + + @ApiOperation( + value = "Logs out current logged in user session", + nickname = "logoutUser", + notes = "") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user/logout"], + method = [RequestMethod.GET]) + fun logoutUser(): ResponseEntity { + return ResponseEntity(service.logoutUser(), HttpStatus.OK) + } + + @ApiOperation( + value = "Updated user", + nickname = "updateUser", + notes = "This can only be done by the logged in user.") + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid user supplied"),ApiResponse(code = 404, message = "User not found")]) + @RequestMapping( + value = ["/user/{username}"], + consumes = ["application/json"], + method = [RequestMethod.PUT]) + fun updateUser(@ApiParam(value = "name that need to be deleted", required=true) @PathVariable("username") username: kotlin.String,@ApiParam(value = "Updated user object" ,required=true ) @RequestBody user: User): ResponseEntity { + return ResponseEntity(service.updateUser(username, user), HttpStatus.OK) + } +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt new file mode 100644 index 000000000000..4b913ace3dba --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt @@ -0,0 +1,22 @@ +package org.openapitools.api + +import org.openapitools.model.User + +interface UserApiService { + + fun createUser(user: User): Unit + + fun createUsersWithArrayInput(user: kotlin.Array): Unit + + fun createUsersWithListInput(user: kotlin.Array): Unit + + fun deleteUser(username: kotlin.String): Unit + + fun getUserByName(username: kotlin.String): User + + fun loginUser(username: kotlin.String,password: kotlin.String): kotlin.String + + fun logoutUser(): Unit + + fun updateUser(username: kotlin.String,user: User): Unit +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt new file mode 100644 index 000000000000..9600f607688e --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt @@ -0,0 +1,40 @@ +package org.openapitools.api + +import org.openapitools.model.User +import org.springframework.stereotype.Service + +@Service +class UserApiServiceImpl : UserApiService { + + override fun createUser(user: User): Unit { + TODO("Implement me") + } + + override fun createUsersWithArrayInput(user: kotlin.Array): Unit { + TODO("Implement me") + } + + override fun createUsersWithListInput(user: kotlin.Array): Unit { + TODO("Implement me") + } + + override fun deleteUser(username: kotlin.String): Unit { + TODO("Implement me") + } + + override fun getUserByName(username: kotlin.String): User { + TODO("Implement me") + } + + override fun loginUser(username: kotlin.String,password: kotlin.String): kotlin.String { + TODO("Implement me") + } + + override fun logoutUser(): Unit { + TODO("Implement me") + } + + override fun updateUser(username: kotlin.String,user: User): Unit { + TODO("Implement me") + } +} diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt new file mode 100644 index 000000000000..d37545dc03be --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt @@ -0,0 +1,19 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A category for a pet + * @param id + * @param name + */ +data class Category ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("name") val name: kotlin.String? = null +) { + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt new file mode 100644 index 000000000000..0ac2323e8dd0 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt @@ -0,0 +1,21 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * Describes the result of uploading an image resource + * @param code + * @param type + * @param message + */ +data class ModelApiResponse ( + @JsonProperty("code") val code: kotlin.Int? = null, + @JsonProperty("type") val type: kotlin.String? = null, + @JsonProperty("message") val message: kotlin.String? = null +) { + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt new file mode 100644 index 000000000000..5d8e3d60e858 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -0,0 +1,43 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonValue +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * An order for a pets from the pet store + * @param id + * @param petId + * @param quantity + * @param shipDate + * @param status Order Status + * @param complete + */ +data class Order ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("petId") val petId: kotlin.Long? = null, + @JsonProperty("quantity") val quantity: kotlin.Int? = null, + @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + /* Order Status */ + @JsonProperty("status") val status: Order.Status? = null, + @JsonProperty("complete") val complete: kotlin.Boolean? = null +) { + + /** + * Order Status + * Values: placed,approved,delivered + */ + enum class Status(val value: kotlin.String) { + + @JsonProperty("placed") placed("placed"), + + @JsonProperty("approved") approved("approved"), + + @JsonProperty("delivered") delivered("delivered"); + + } + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt new file mode 100644 index 000000000000..829a70a238a6 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt @@ -0,0 +1,45 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonValue +import org.openapitools.model.Category +import org.openapitools.model.Tag +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A pet for sale in the pet store + * @param id + * @param category + * @param name + * @param photoUrls + * @param tags + * @param status pet status in the store + */ +data class Pet ( + @JsonProperty("name") val name: kotlin.String, + @JsonProperty("photoUrls") val photoUrls: kotlin.Array, + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("category") val category: Category? = null, + @JsonProperty("tags") val tags: kotlin.Array? = null, + /* pet status in the store */ + @JsonProperty("status") val status: Pet.Status? = null +) { + + /** + * pet status in the store + * Values: available,pending,sold + */ + enum class Status(val value: kotlin.String) { + + @JsonProperty("available") available("available"), + + @JsonProperty("pending") pending("pending"), + + @JsonProperty("sold") sold("sold"); + + } + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt new file mode 100644 index 000000000000..4c409816464a --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt @@ -0,0 +1,19 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A tag for a pet + * @param id + * @param name + */ +data class Tag ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("name") val name: kotlin.String? = null +) { + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt new file mode 100644 index 000000000000..4e7e729b2639 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt @@ -0,0 +1,32 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A User who is purchasing from the pet store + * @param id + * @param username + * @param firstName + * @param lastName + * @param email + * @param password + * @param phone + * @param userStatus User Status + */ +data class User ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("username") val username: kotlin.String? = null, + @JsonProperty("firstName") val firstName: kotlin.String? = null, + @JsonProperty("lastName") val lastName: kotlin.String? = null, + @JsonProperty("email") val email: kotlin.String? = null, + @JsonProperty("password") val password: kotlin.String? = null, + @JsonProperty("phone") val phone: kotlin.String? = null, + /* User Status */ + @JsonProperty("userStatus") val userStatus: kotlin.Int? = null +) { + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/resources/application.yaml b/samples/server/openapi3/petstore/kotlin-springboot/src/main/resources/application.yaml new file mode 100644 index 000000000000..366e320d52cf --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/resources/application.yaml @@ -0,0 +1,3 @@ +spring.application.name=openAPIPetstore +server.port=8080 +spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false \ No newline at end of file diff --git a/samples/server/petstore/kotlin-springboot/.openapi-generator-ignore b/samples/server/petstore/kotlin-springboot/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION b/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION new file mode 100644 index 000000000000..105bb87d77b3 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION @@ -0,0 +1 @@ +3.2.2-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/kotlin-springboot/build.gradle.kts b/samples/server/petstore/kotlin-springboot/build.gradle.kts new file mode 100644 index 000000000000..79962e285bbf --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/build.gradle.kts @@ -0,0 +1,43 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +buildscript { + repositories { + jcenter() + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE") + } +} + +group = "org.openapitools" +version = "1.0.0" + +repositories { + jcenter() + mavenCentral() +} + +tasks.withType { + kotlinOptions.jvmTarget = "1.8" +} + +plugins { + val kotlinVersion = "1.2.41" + id("org.jetbrains.kotlin.jvm") version kotlinVersion + id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion + id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion + id("org.springframework.boot") version "2.0.3.RELEASE" + id("io.spring.dependency-management") version "1.0.5.RELEASE" +} + +dependencies { + compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + compile("org.jetbrains.kotlin:kotlin-reflect") + compile("org.springframework.boot:spring-boot-starter-web") + compile("io.swagger:swagger-annotations:1.5.14") + + testCompile("org.springframework.boot:spring-boot-starter-test") { + exclude(module = "junit") + } +} diff --git a/samples/server/petstore/kotlin-springboot/pom.xml b/samples/server/petstore/kotlin-springboot/pom.xml new file mode 100644 index 000000000000..0b29122357e7 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/pom.xml @@ -0,0 +1,96 @@ + + 4.0.0 + org.openapitools + openapi-spring + jar + openapi-spring + 1.0.0 + + 1.2.41 + + + org.springframework.boot + spring-boot-starter-parent + 2.0.3.RELEASE + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + + spring + + 1.8 + + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + org.springframework.boot + spring-boot-starter-web + + + io.swagger + swagger-annotations + 1.5.14 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + diff --git a/samples/server/petstore/kotlin-springboot/settings.gradle b/samples/server/petstore/kotlin-springboot/settings.gradle new file mode 100644 index 000000000000..f0dd035311e0 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "openapi-spring" \ No newline at end of file diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt new file mode 100644 index 000000000000..f2ee49d476b6 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/Application.kt @@ -0,0 +1,14 @@ +package org.openapitools + +import org.springframework.boot.runApplication +import org.springframework.context.annotation.ComponentScan +import org.springframework.boot.autoconfigure.SpringBootApplication + + +@SpringBootApplication +@ComponentScan(basePackages = ["org.openapitools", "org.openapitools.api", "org.openapitools.model"]) +class Application + +fun main(args: Array) { + runApplication(*args) +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt new file mode 100644 index 000000000000..afba2986af28 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -0,0 +1,24 @@ +package org.openapitools.api + +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ControllerAdvice +import org.springframework.web.bind.annotation.ExceptionHandler +import javax.servlet.http.HttpServletRequest + +sealed class ApiException(msg: String, val code: Int) : Exception(msg) + +class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) + + +@ControllerAdvice +class DefaultExceptionHandler { + + @ExceptionHandler(value = [NotFoundException::class]) + fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.valueOf(ex.code)) + + @ExceptionHandler(value = [NotImplementedError::class]) + fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.NOT_IMPLEMENTED) +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt new file mode 100644 index 000000000000..d7e2a4729324 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -0,0 +1,154 @@ +package org.openapitools.api + +import org.openapitools.model.ModelApiResponse +import org.openapitools.model.Pet +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile +import org.springframework.beans.factory.annotation.Autowired + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +@Api(value = "Pet", description = "The Pet API") +@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") +class PetApiController(@Autowired(required = true) val service: PetApiService) { + + @ApiOperation( + value = "Add a new pet to the store", + nickname = "addPet", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 405, message = "Invalid input")]) + @RequestMapping( + value = ["/pet"], + consumes = ["application/json", "application/xml"], + method = [RequestMethod.POST]) + fun addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + return ResponseEntity(service.addPet(pet), HttpStatus.OK) + } + + @ApiOperation( + value = "Deletes a pet", + nickname = "deletePet", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid pet value")]) + @RequestMapping( + value = ["/pet/{petId}"], + method = [RequestMethod.DELETE]) + fun deletePet(@ApiParam(value = "Pet id to delete", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "" ) @RequestHeader(value="api_key", required=false) apiKey: kotlin.String): ResponseEntity { + return ResponseEntity(service.deletePet(petId, apiKey), HttpStatus.OK) + } + + @ApiOperation( + value = "Finds Pets by status", + nickname = "findPetsByStatus", + notes = "Multiple status values can be provided with comma separated strings", + response = Pet::class, + responseContainer = "List", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid status value")]) + @RequestMapping( + value = ["/pet/findByStatus"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun findPetsByStatus(@ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @RequestParam(value = "status", required = true) status: kotlin.Array): ResponseEntity> { + return ResponseEntity(service.findPetsByStatus(status), HttpStatus.OK) + } + + @ApiOperation( + value = "Finds Pets by tags", + nickname = "findPetsByTags", + notes = "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + response = Pet::class, + responseContainer = "List", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid tag value")]) + @RequestMapping( + value = ["/pet/findByTags"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun findPetsByTags(@ApiParam(value = "Tags to filter by", required = true) @RequestParam(value = "tags", required = true) tags: kotlin.Array): ResponseEntity> { + return ResponseEntity(service.findPetsByTags(tags), HttpStatus.OK) + } + + @ApiOperation( + value = "Find pet by ID", + nickname = "getPetById", + notes = "Returns a single pet", + response = Pet::class, + authorizations = [Authorization(value = "api_key")]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Pet not found")]) + @RequestMapping( + value = ["/pet/{petId}"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun getPetById(@ApiParam(value = "ID of pet to return", required=true) @PathVariable("petId") petId: kotlin.Long): ResponseEntity { + return ResponseEntity(service.getPetById(petId), HttpStatus.OK) + } + + @ApiOperation( + value = "Update an existing pet", + nickname = "updatePet", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Pet not found"),ApiResponse(code = 405, message = "Validation exception")]) + @RequestMapping( + value = ["/pet"], + consumes = ["application/json", "application/xml"], + method = [RequestMethod.PUT]) + fun updatePet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + return ResponseEntity(service.updatePet(pet), HttpStatus.OK) + } + + @ApiOperation( + value = "Updates a pet in the store with form data", + nickname = "updatePetWithForm", + notes = "", + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 405, message = "Invalid input")]) + @RequestMapping( + value = ["/pet/{petId}"], + consumes = ["application/x-www-form-urlencoded"], + method = [RequestMethod.POST]) + fun updatePetWithForm(@ApiParam(value = "ID of pet that needs to be updated", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Updated name of the pet", defaultValue="null") @RequestParam(value="name", required=false) name: kotlin.String ,@ApiParam(value = "Updated status of the pet", defaultValue="null") @RequestParam(value="status", required=false) status: kotlin.String ): ResponseEntity { + return ResponseEntity(service.updatePetWithForm(petId, name, status), HttpStatus.OK) + } + + @ApiOperation( + value = "uploads an image", + nickname = "uploadFile", + notes = "", + response = ModelApiResponse::class, + authorizations = [Authorization(value = "petstore_auth", scopes = [AuthorizationScope(scope = "write:pets", description = "modify pets in your account"), AuthorizationScope(scope = "read:pets", description = "read your pets")])]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = ModelApiResponse::class)]) + @RequestMapping( + value = ["/pet/{petId}/uploadImage"], + produces = ["application/json"], + consumes = ["multipart/form-data"], + method = [RequestMethod.POST]) + fun uploadFile(@ApiParam(value = "ID of pet to update", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Additional data to pass to server", defaultValue="null") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: kotlin.String ,@ApiParam(value = "file detail") @RequestPart("file") file: MultipartFile): ResponseEntity { + return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK) + } +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt new file mode 100644 index 000000000000..e7bd7fae34ef --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiService.kt @@ -0,0 +1,23 @@ +package org.openapitools.api + +import org.openapitools.model.ModelApiResponse +import org.openapitools.model.Pet + +interface PetApiService { + + fun addPet(pet: Pet): Unit + + fun deletePet(petId: kotlin.Long,apiKey: kotlin.String): Unit + + fun findPetsByStatus(status: kotlin.Array): List + + fun findPetsByTags(tags: kotlin.Array): List + + fun getPetById(petId: kotlin.Long): Pet + + fun updatePet(pet: Pet): Unit + + fun updatePetWithForm(petId: kotlin.Long,name: kotlin.String,status: kotlin.String): Unit + + fun uploadFile(petId: kotlin.Long,additionalMetadata: kotlin.String,file: org.springframework.web.multipart.MultipartFile): ModelApiResponse +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt new file mode 100644 index 000000000000..e898ab98921b --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApiServiceImpl.kt @@ -0,0 +1,41 @@ +package org.openapitools.api + +import org.openapitools.model.ModelApiResponse +import org.openapitools.model.Pet +import org.springframework.stereotype.Service + +@Service +class PetApiServiceImpl : PetApiService { + + override fun addPet(pet: Pet): Unit { + TODO("Implement me") + } + + override fun deletePet(petId: kotlin.Long,apiKey: kotlin.String): Unit { + TODO("Implement me") + } + + override fun findPetsByStatus(status: kotlin.Array): List { + TODO("Implement me") + } + + override fun findPetsByTags(tags: kotlin.Array): List { + TODO("Implement me") + } + + override fun getPetById(petId: kotlin.Long): Pet { + TODO("Implement me") + } + + override fun updatePet(pet: Pet): Unit { + TODO("Implement me") + } + + override fun updatePetWithForm(petId: kotlin.Long,name: kotlin.String,status: kotlin.String): Unit { + TODO("Implement me") + } + + override fun uploadFile(petId: kotlin.Long,additionalMetadata: kotlin.String,file: org.springframework.web.multipart.MultipartFile): ModelApiResponse { + TODO("Implement me") + } +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt new file mode 100644 index 000000000000..db13ad07f700 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt @@ -0,0 +1,87 @@ +package org.openapitools.api + +import org.openapitools.model.Order +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile +import org.springframework.beans.factory.annotation.Autowired + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +@Api(value = "Store", description = "The Store API") +@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") +class StoreApiController(@Autowired(required = true) val service: StoreApiService) { + + @ApiOperation( + value = "Delete purchase order by ID", + nickname = "deleteOrder", + notes = "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors") + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Order not found")]) + @RequestMapping( + value = ["/store/order/{orderId}"], + method = [RequestMethod.DELETE]) + fun deleteOrder(@ApiParam(value = "ID of the order that needs to be deleted", required=true) @PathVariable("orderId") orderId: kotlin.String): ResponseEntity { + return ResponseEntity(service.deleteOrder(orderId), HttpStatus.OK) + } + + @ApiOperation( + value = "Returns pet inventories by status", + nickname = "getInventory", + notes = "Returns a map of status codes to quantities", + response = kotlin.Int::class, + responseContainer = "Map", + authorizations = [Authorization(value = "api_key")]) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = kotlin.collections.Map::class, responseContainer = "Map")]) + @RequestMapping( + value = ["/store/inventory"], + produces = ["application/json"], + method = [RequestMethod.GET]) + fun getInventory(): ResponseEntity> { + return ResponseEntity(service.getInventory(), HttpStatus.OK) + } + + @ApiOperation( + value = "Find purchase order by ID", + nickname = "getOrderById", + notes = "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions", + response = Order::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Order not found")]) + @RequestMapping( + value = ["/store/order/{orderId}"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun getOrderById(@ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity { + return ResponseEntity(service.getOrderById(orderId), HttpStatus.OK) + } + + @ApiOperation( + value = "Place an order for a pet", + nickname = "placeOrder", + notes = "", + response = Order::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid Order")]) + @RequestMapping( + value = ["/store/order"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.POST]) + fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @RequestBody order: Order): ResponseEntity { + return ResponseEntity(service.placeOrder(order), HttpStatus.OK) + } +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt new file mode 100644 index 000000000000..5eb379cb1854 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiService.kt @@ -0,0 +1,14 @@ +package org.openapitools.api + +import org.openapitools.model.Order + +interface StoreApiService { + + fun deleteOrder(orderId: kotlin.String): Unit + + fun getInventory(): Map + + fun getOrderById(orderId: kotlin.Long): Order + + fun placeOrder(order: Order): Order +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt new file mode 100644 index 000000000000..87d2551740d3 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApiServiceImpl.kt @@ -0,0 +1,24 @@ +package org.openapitools.api + +import org.openapitools.model.Order +import org.springframework.stereotype.Service + +@Service +class StoreApiServiceImpl : StoreApiService { + + override fun deleteOrder(orderId: kotlin.String): Unit { + TODO("Implement me") + } + + override fun getInventory(): Map { + TODO("Implement me") + } + + override fun getOrderById(orderId: kotlin.Long): Order { + TODO("Implement me") + } + + override fun placeOrder(order: Order): Order { + TODO("Implement me") + } +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt new file mode 100644 index 000000000000..6b8e13f04ced --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt @@ -0,0 +1,135 @@ +package org.openapitools.api + +import org.openapitools.model.User +import io.swagger.annotations.* +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.context.request.NativeWebRequest +import org.springframework.web.multipart.MultipartFile +import org.springframework.beans.factory.annotation.Autowired + +import kotlin.collections.List +import kotlin.collections.Map + +@Controller +@Api(value = "User", description = "The User API") +@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") +class UserApiController(@Autowired(required = true) val service: UserApiService) { + + @ApiOperation( + value = "Create user", + nickname = "createUser", + notes = "This can only be done by the logged in user.") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user"], + method = [RequestMethod.POST]) + fun createUser(@ApiParam(value = "Created user object" ,required=true ) @RequestBody user: User): ResponseEntity { + return ResponseEntity(service.createUser(user), HttpStatus.OK) + } + + @ApiOperation( + value = "Creates list of users with given input array", + nickname = "createUsersWithArrayInput", + notes = "") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user/createWithArray"], + method = [RequestMethod.POST]) + fun createUsersWithArrayInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + return ResponseEntity(service.createUsersWithArrayInput(user), HttpStatus.OK) + } + + @ApiOperation( + value = "Creates list of users with given input array", + nickname = "createUsersWithListInput", + notes = "") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user/createWithList"], + method = [RequestMethod.POST]) + fun createUsersWithListInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + return ResponseEntity(service.createUsersWithListInput(user), HttpStatus.OK) + } + + @ApiOperation( + value = "Delete user", + nickname = "deleteUser", + notes = "This can only be done by the logged in user.") + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid username supplied"),ApiResponse(code = 404, message = "User not found")]) + @RequestMapping( + value = ["/user/{username}"], + method = [RequestMethod.DELETE]) + fun deleteUser(@ApiParam(value = "The name that needs to be deleted", required=true) @PathVariable("username") username: kotlin.String): ResponseEntity { + return ResponseEntity(service.deleteUser(username), HttpStatus.OK) + } + + @ApiOperation( + value = "Get user by user name", + nickname = "getUserByName", + notes = "", + response = User::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = User::class),ApiResponse(code = 400, message = "Invalid username supplied"),ApiResponse(code = 404, message = "User not found")]) + @RequestMapping( + value = ["/user/{username}"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun getUserByName(@ApiParam(value = "The name that needs to be fetched. Use user1 for testing.", required=true) @PathVariable("username") username: kotlin.String): ResponseEntity { + return ResponseEntity(service.getUserByName(username), HttpStatus.OK) + } + + @ApiOperation( + value = "Logs user into the system", + nickname = "loginUser", + notes = "", + response = kotlin.String::class) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = kotlin.String::class),ApiResponse(code = 400, message = "Invalid username/password supplied")]) + @RequestMapping( + value = ["/user/login"], + produces = ["application/xml", "application/json"], + method = [RequestMethod.GET]) + fun loginUser(@ApiParam(value = "The user name for login", required = true) @RequestParam(value = "username", required = true) username: kotlin.String,@ApiParam(value = "The password for login in clear text", required = true) @RequestParam(value = "password", required = true) password: kotlin.String): ResponseEntity { + return ResponseEntity(service.loginUser(username, password), HttpStatus.OK) + } + + @ApiOperation( + value = "Logs out current logged in user session", + nickname = "logoutUser", + notes = "") + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation")]) + @RequestMapping( + value = ["/user/logout"], + method = [RequestMethod.GET]) + fun logoutUser(): ResponseEntity { + return ResponseEntity(service.logoutUser(), HttpStatus.OK) + } + + @ApiOperation( + value = "Updated user", + nickname = "updateUser", + notes = "This can only be done by the logged in user.") + @ApiResponses( + value = [ApiResponse(code = 400, message = "Invalid user supplied"),ApiResponse(code = 404, message = "User not found")]) + @RequestMapping( + value = ["/user/{username}"], + method = [RequestMethod.PUT]) + fun updateUser(@ApiParam(value = "name that need to be deleted", required=true) @PathVariable("username") username: kotlin.String,@ApiParam(value = "Updated user object" ,required=true ) @RequestBody user: User): ResponseEntity { + return ResponseEntity(service.updateUser(username, user), HttpStatus.OK) + } +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt new file mode 100644 index 000000000000..4b913ace3dba --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiService.kt @@ -0,0 +1,22 @@ +package org.openapitools.api + +import org.openapitools.model.User + +interface UserApiService { + + fun createUser(user: User): Unit + + fun createUsersWithArrayInput(user: kotlin.Array): Unit + + fun createUsersWithListInput(user: kotlin.Array): Unit + + fun deleteUser(username: kotlin.String): Unit + + fun getUserByName(username: kotlin.String): User + + fun loginUser(username: kotlin.String,password: kotlin.String): kotlin.String + + fun logoutUser(): Unit + + fun updateUser(username: kotlin.String,user: User): Unit +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt new file mode 100644 index 000000000000..9600f607688e --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApiServiceImpl.kt @@ -0,0 +1,40 @@ +package org.openapitools.api + +import org.openapitools.model.User +import org.springframework.stereotype.Service + +@Service +class UserApiServiceImpl : UserApiService { + + override fun createUser(user: User): Unit { + TODO("Implement me") + } + + override fun createUsersWithArrayInput(user: kotlin.Array): Unit { + TODO("Implement me") + } + + override fun createUsersWithListInput(user: kotlin.Array): Unit { + TODO("Implement me") + } + + override fun deleteUser(username: kotlin.String): Unit { + TODO("Implement me") + } + + override fun getUserByName(username: kotlin.String): User { + TODO("Implement me") + } + + override fun loginUser(username: kotlin.String,password: kotlin.String): kotlin.String { + TODO("Implement me") + } + + override fun logoutUser(): Unit { + TODO("Implement me") + } + + override fun updateUser(username: kotlin.String,user: User): Unit { + TODO("Implement me") + } +} diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt new file mode 100644 index 000000000000..d37545dc03be --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt @@ -0,0 +1,19 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A category for a pet + * @param id + * @param name + */ +data class Category ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("name") val name: kotlin.String? = null +) { + +} + diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt new file mode 100644 index 000000000000..0ac2323e8dd0 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt @@ -0,0 +1,21 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * Describes the result of uploading an image resource + * @param code + * @param type + * @param message + */ +data class ModelApiResponse ( + @JsonProperty("code") val code: kotlin.Int? = null, + @JsonProperty("type") val type: kotlin.String? = null, + @JsonProperty("message") val message: kotlin.String? = null +) { + +} + diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt new file mode 100644 index 000000000000..5d8e3d60e858 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -0,0 +1,43 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonValue +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * An order for a pets from the pet store + * @param id + * @param petId + * @param quantity + * @param shipDate + * @param status Order Status + * @param complete + */ +data class Order ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("petId") val petId: kotlin.Long? = null, + @JsonProperty("quantity") val quantity: kotlin.Int? = null, + @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + /* Order Status */ + @JsonProperty("status") val status: Order.Status? = null, + @JsonProperty("complete") val complete: kotlin.Boolean? = null +) { + + /** + * Order Status + * Values: placed,approved,delivered + */ + enum class Status(val value: kotlin.String) { + + @JsonProperty("placed") placed("placed"), + + @JsonProperty("approved") approved("approved"), + + @JsonProperty("delivered") delivered("delivered"); + + } + +} + diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt new file mode 100644 index 000000000000..829a70a238a6 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt @@ -0,0 +1,45 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonValue +import org.openapitools.model.Category +import org.openapitools.model.Tag +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A pet for sale in the pet store + * @param id + * @param category + * @param name + * @param photoUrls + * @param tags + * @param status pet status in the store + */ +data class Pet ( + @JsonProperty("name") val name: kotlin.String, + @JsonProperty("photoUrls") val photoUrls: kotlin.Array, + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("category") val category: Category? = null, + @JsonProperty("tags") val tags: kotlin.Array? = null, + /* pet status in the store */ + @JsonProperty("status") val status: Pet.Status? = null +) { + + /** + * pet status in the store + * Values: available,pending,sold + */ + enum class Status(val value: kotlin.String) { + + @JsonProperty("available") available("available"), + + @JsonProperty("pending") pending("pending"), + + @JsonProperty("sold") sold("sold"); + + } + +} + diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt new file mode 100644 index 000000000000..4c409816464a --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt @@ -0,0 +1,19 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A tag for a pet + * @param id + * @param name + */ +data class Tag ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("name") val name: kotlin.String? = null +) { + +} + diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt new file mode 100644 index 000000000000..4e7e729b2639 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt @@ -0,0 +1,32 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* + +/** + * A User who is purchasing from the pet store + * @param id + * @param username + * @param firstName + * @param lastName + * @param email + * @param password + * @param phone + * @param userStatus User Status + */ +data class User ( + @JsonProperty("id") val id: kotlin.Long? = null, + @JsonProperty("username") val username: kotlin.String? = null, + @JsonProperty("firstName") val firstName: kotlin.String? = null, + @JsonProperty("lastName") val lastName: kotlin.String? = null, + @JsonProperty("email") val email: kotlin.String? = null, + @JsonProperty("password") val password: kotlin.String? = null, + @JsonProperty("phone") val phone: kotlin.String? = null, + /* User Status */ + @JsonProperty("userStatus") val userStatus: kotlin.Int? = null +) { + +} + diff --git a/samples/server/petstore/kotlin-springboot/src/main/resources/application.yaml b/samples/server/petstore/kotlin-springboot/src/main/resources/application.yaml new file mode 100644 index 000000000000..366e320d52cf --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/src/main/resources/application.yaml @@ -0,0 +1,3 @@ +spring.application.name=openAPIPetstore +server.port=8080 +spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false \ No newline at end of file From 7fbf228a565d87282fc2ca326efd19ee036da2a8 Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Mon, 20 Aug 2018 06:46:41 -0400 Subject: [PATCH 27/39] Minor fixes from PR comments for user submission (#1) * Minor fixes from PR comments for user submission * Puts braces around conditional block bodies with one-liner bodies. * Modifies README.mustache to use artifact id and version supplied by user (or default configuration) * Targets templates under resource directory explicitly to prevent the need to rebuild for evaluation of template-only changes. * [kotlin-spring] Remove comments referencing sbt in bash scripts --- bin/kotlin-springboot-petstore-server.sh | 3 +-- .../kotlin-springboot-petstore-server.sh | 3 +-- .../languages/AbstractKotlinCodegen.java | 17 +++++++++++------ .../languages/KotlinSpringServerCodegen.java | 18 +++++++++++------- .../libraries/spring-boot/README.mustache | 4 ++-- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/bin/kotlin-springboot-petstore-server.sh b/bin/kotlin-springboot-petstore-server.sh index a24fff41a68a..53eabc278a78 100755 --- a/bin/kotlin-springboot-petstore-server.sh +++ b/bin/kotlin-springboot-petstore-server.sh @@ -25,9 +25,8 @@ then mvn clean package fi -# if you've executed sbt assembly previously it will use that instead. export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g kotlin-spring -o samples/server/petstore/kotlin-springboot --additional-properties=library=spring-boot" +ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/petstore/kotlin-springboot --additional-properties=library=spring-boot" echo "Cleaning previously generated files if any from samples/server/petstore/kotlin-springboot" rm -rf samples/server/petstore/kotlin-springboot diff --git a/bin/openapi3/kotlin-springboot-petstore-server.sh b/bin/openapi3/kotlin-springboot-petstore-server.sh index 01331f4f8c64..26dc12be2324 100755 --- a/bin/openapi3/kotlin-springboot-petstore-server.sh +++ b/bin/openapi3/kotlin-springboot-petstore-server.sh @@ -25,9 +25,8 @@ then mvn clean package fi -# if you've executed sbt assembly previously it will use that instead. export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -g kotlin-spring -o samples/server/openapi3/petstore/kotlin-springboot --additional-properties=library=spring-boot" +ags="$@ generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/openapi3/petstore/kotlin-springboot --additional-properties=library=spring-boot" echo "Cleaning previously generated files if any from samples/server/openapi3/petstore/kotlin-springboot" rm -rf samples/server/openapi3/petstore/kotlin-springboot diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index c7d03133fa3b..4055f99bad9b 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -634,21 +634,25 @@ public String toVarName(String name) { // sanitize name name = sanitizeName(name, "\\W-[\\$]"); - if (name.toLowerCase().matches("^_*class$")) + if (name.toLowerCase().matches("^_*class$")) { return "propertyClass"; + } - if ("_".equals(name)) + if ("_".equals(name)) { name = "_u"; + } // if it's all uppper case, do nothing - if (name.matches("^[A-Z_]*$")) + if (name.matches("^[A-Z_]*$")) { return name; + } - if (startsWithTwoUppercaseLetters(name)) + if (startsWithTwoUppercaseLetters(name)) { name = name.substring(0, 2).toLowerCase() + name.substring(2); + } // If name contains special chars -> replace them. - if ((((CharSequence) name).chars().anyMatch(character -> specialCharReplacements.keySet().contains("" + ((char) character))))) { + if ((name.chars().anyMatch(character -> specialCharReplacements.keySet().contains("" + ((char) character))))) { List allowedCharacters = new ArrayList<>(); allowedCharacters.add("_"); allowedCharacters.add("$"); @@ -660,8 +664,9 @@ public String toVarName(String name) { name = camelize(name, true); // for reserved word or word starting with number or containing dollar symbol, escape it - if (isReservedWord(name) || name.matches("(^\\d.*)|(.*[$].*)")) + if (isReservedWord(name) || name.matches("(^\\d.*)|(.*[$].*)")) { name = escapeReservedWord(name); + } return name; } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 4865afd9e0d6..e8ee7c100b55 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -62,9 +62,6 @@ public KotlinSpringServerCodegen() { apiPackage = "org.openapitools.api"; modelPackage = "org.openapitools.model"; - // spring uses the jackson lib - additionalProperties.put("jackson", "true"); - addOption(TITLE, "server title name or client service name", title); addOption(BASE_PACKAGE, "base package for generated code", basePackage); addOption(SERVER_PORT, "configuration the port in which the sever is to run on", serverPort); @@ -284,6 +281,9 @@ public void processOpts() { (Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("\"", Matcher.quoteReplacement("\\\"")))); additionalProperties.put("lambdaRemoveLineBreak", (Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("\\r|\\n", ""))); + + // spring uses the jackson lib, and we disallow configuration. + additionalProperties.put("jackson", "true"); } @Override @@ -322,19 +322,22 @@ public void preprocessOpenAPI(OpenAPI openAPI) { public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { super.postProcessModelProperty(model, property); - if ("null".equals(property.example)) + if ("null".equals(property.example)) { property.example = null; + } //Add imports for Jackson if (!Boolean.TRUE.equals(model.isEnum)) { model.imports.add("JsonProperty"); - if (Boolean.TRUE.equals(model.hasEnums)) + if (Boolean.TRUE.equals(model.hasEnums)) { model.imports.add("JsonValue"); + } } else { //Needed imports for Jackson's JsonCreator - if (additionalProperties.containsKey("jackson")) + if (additionalProperties.containsKey("jackson")) { model.imports.add("JsonCreator"); + } } } @@ -371,8 +374,9 @@ public Map postProcessOperationsWithModels(Map o if (responses != null) { responses.forEach(resp -> { - if ("0".equals(resp.code)) + if ("0".equals(resp.code)) { resp.code = "200"; + } doDataTypeAssignment(resp.dataType, new DataTypeAssigner() { @Override diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache index 736509fe212b..b29d99926c78 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache @@ -10,12 +10,12 @@ By default a [`pom.xml`](pom.xml) file will be generated. If you specified `grad To build the project using maven, run: ```bash -mvn package && java -jar target/openapi-spring-1.0.0.jar +mvn package && java -jar target/{{artifactId}}-{{artifactVersion}}.jar ``` To build the project using gradle, run: ```bash -gradle build && java -jar build/libs/openapi-spring-1.0.0.jar +gradle build && java -jar build/libs/{{artifactId}}-{{artifactVersion}}.jar ``` If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:8080/) From 91b9aaa7455b85990fec1d7f22bec43a0cff370f Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Mon, 20 Aug 2018 15:24:57 +0100 Subject: [PATCH 28/39] List of changes based upon code review: * Additional comments around how we set the title based off the open api spec * Fixed missing `beanValidationCore` template * Put the lambdas into the lambda object as other generators do (Ktor, C#, cpp) * Bump swagger-annotations version to latest pre-2.0 version (1.5.21) * Set kotlin version to 1.2.60 * Updated README to set port based on template * Added more additional properties to build bash scripts * Removed `defaultBasePath.mustache` in place of using {{contextPath}} directly * Log warning for when `serviceImplementation` is set t o true --- bin/kotlin-springboot-petstore-server.sh | 2 +- .../kotlin-springboot-petstore-server.sh | 2 +- .../languages/KotlinSpringServerCodegen.java | 48 ++++++++++++++++--- .../main/resources/kotlin-spring/api.mustache | 4 +- .../beanValidationQueryParams.mustache | 2 +- .../libraries/spring-boot/README.mustache | 2 +- .../spring-boot/buildGradleKts.mustache | 4 +- .../spring-boot/defaultBasePath.mustache | 1 - .../libraries/spring-boot/pom.mustache | 4 +- .../kotlin-spring/pathParams.mustache | 2 +- 10 files changed, 53 insertions(+), 18 deletions(-) delete mode 100644 modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache diff --git a/bin/kotlin-springboot-petstore-server.sh b/bin/kotlin-springboot-petstore-server.sh index 53eabc278a78..7e1c3888c8f0 100755 --- a/bin/kotlin-springboot-petstore-server.sh +++ b/bin/kotlin-springboot-petstore-server.sh @@ -26,7 +26,7 @@ then fi export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/petstore/kotlin-springboot --additional-properties=library=spring-boot" +ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/petstore/kotlin-springboot --additional-properties=library=spring-boot,beanValidations=true,swaggerAnnotations=true,serviceImplementation=true" echo "Cleaning previously generated files if any from samples/server/petstore/kotlin-springboot" rm -rf samples/server/petstore/kotlin-springboot diff --git a/bin/openapi3/kotlin-springboot-petstore-server.sh b/bin/openapi3/kotlin-springboot-petstore-server.sh index 26dc12be2324..3ac7b6f68eb0 100755 --- a/bin/openapi3/kotlin-springboot-petstore-server.sh +++ b/bin/openapi3/kotlin-springboot-petstore-server.sh @@ -26,7 +26,7 @@ then fi export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/openapi3/petstore/kotlin-springboot --additional-properties=library=spring-boot" +ags="$@ generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/openapi3/petstore/kotlin-springboot --additional-properties=library=spring-boot,beanValidations=true,swaggerAnnotations=true,serviceImplementation=true" echo "Cleaning previously generated files if any from samples/server/openapi3/petstore/kotlin-springboot" rm -rf samples/server/openapi3/petstore/kotlin-springboot diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index e8ee7c100b55..24b80113cd17 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -1,6 +1,8 @@ package org.openapitools.codegen.languages; +import com.google.common.collect.ImmutableMap; import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Template; import io.swagger.v3.oas.models.OpenAPI; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.features.BeanValidationFeatures; @@ -9,6 +11,8 @@ import org.slf4j.LoggerFactory; import java.io.File; +import java.io.IOException; +import java.io.Writer; import java.net.URL; import java.util.*; import java.util.regex.Matcher; @@ -28,6 +32,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen )); public static final String TITLE = "title"; + public static final String LAMBDA = "lambda"; public static final String SERVER_PORT = "serverPort"; public static final String BASE_PACKAGE = "basePackage"; public static final String SPRING_BOOT = "spring-boot"; @@ -252,6 +257,7 @@ public void processOpts() { if (this.serviceInterface) { apiTemplateFiles.put("service.mustache", "Service.kt"); } else if (this.serviceImplementation) { + LOGGER.warn("If you set `serviceImplementation` to true, `serviceInterface` will also be set to true"); additionalProperties.put(SERVICE_INTERFACE, true); apiTemplateFiles.put("service.mustache", "Service.kt"); apiTemplateFiles.put("serviceImpl.mustache", "ServiceImpl.kt"); @@ -276,16 +282,24 @@ public void processOpts() { sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); } - // add lambda for mustache templates - additionalProperties.put("lambdaEscapeDoubleQuote", - (Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("\"", Matcher.quoteReplacement("\\\"")))); - additionalProperties.put("lambdaRemoveLineBreak", - (Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("\\r|\\n", ""))); + addMustacheLambdas(additionalProperties); // spring uses the jackson lib, and we disallow configuration. additionalProperties.put("jackson", "true"); } + private void addMustacheLambdas(final Map objs) { + Map lambdas = + new ImmutableMap.Builder() + .put("escapeDoubleQuote", new EscapeLambda("\"", "\\\"")) + .build(); + + if (objs.containsKey(LAMBDA)) { + LOGGER.warn("The lambda property is a reserved word, and will be overwritten!"); + } + objs.put(LAMBDA, lambdas); + } + @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); @@ -296,7 +310,13 @@ public void preprocessOpenAPI(OpenAPI openAPI) { */ if (!additionalProperties.containsKey(TITLE)) { - // From the title, compute a reasonable name for the package and the API + // The purpose of the title is for: + // - README documentation + // - The spring.application.name + // - And linking the @RequestMapping + // This is an additional step we add when pre-processing the API spec, if + // there is no user configuration set for the `title` of the project, + // we try build and normalise a title from the API spec itself. String title = openAPI.getInfo().getTitle(); // Drop any API suffix @@ -443,4 +463,20 @@ private void doDataTypeAssignment(final String returnType, DataTypeAssigner data private static String sanitizeDirectory(String in) { return in.replace(".", File.separator); } + + // TODO could probably be made more generic, and moved to the `mustache` package if required by other components. + private static class EscapeLambda implements Mustache.Lambda { + private String from; + private String to; + + EscapeLambda(final String from, final String to) { + this.from = from; + this.to = Matcher.quoteReplacement(to); + } + + @Override + public void execute(Template.Fragment fragment, Writer writer) throws IOException { + writer.write(fragment.execute().replaceAll(from, to)); + } + } } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index 2ea2299c0f67..0ab788eea197 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -39,7 +39,7 @@ import kotlin.collections.Map @Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API") {{/swaggerAnnotations}} {{=<% %>=}} -@RequestMapping("\${openapi.<%title%>.base-path:<%>defaultBasePath%>}") +@RequestMapping("\${openapi.<%title%>.base-path:<%contextPath%>}") <%={{ }}=%> {{#operations}} class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) val service: {{classname}}Service{{/serviceInterface}}) { @@ -56,7 +56,7 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v @ApiResponses( value = [{{#responses}}ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{baseType}}}::class{{/baseType}}{{#containerType}}, responseContainer = "{{{containerType}}}"{{/containerType}}){{#hasMore}},{{/hasMore}}{{/responses}}]){{/swaggerAnnotations}} @RequestMapping( - value = ["{{{path}}}"],{{#singleContentTypes}}{{#hasProduces}} + value = ["{{#lambda.escapeDoubleQuote}}{{path}}{{/lambda.escapeDoubleQuote}}"],{{#singleContentTypes}}{{#hasProduces}} produces = "{{{vendorExtensions.x-accepts}}}", {{/hasProduces}}{{#hasConsumes}} consumes = "{{{vendorExtensions.x-contentType}}}",{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}} produces = [{{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}}], {{/hasProduces}}{{#hasConsumes}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache index 9cca8cb88748..cc53bc96232d 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/beanValidationQueryParams.mustache @@ -1 +1 @@ -{{#required}}@NotNull {{/required}}{{>beanValidationCore}} \ No newline at end of file +{{#required}}@NotNull {{/required}}{{>beanValidationPath}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache index b29d99926c78..9c347d4db0fe 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache @@ -18,4 +18,4 @@ To build the project using gradle, run: gradle build && java -jar build/libs/{{artifactId}}-{{artifactVersion}}.jar ``` -If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:8080/) +If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:{{port}}/) diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache index ad709f4812d8..e4d6aa6d365a 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache @@ -23,7 +23,7 @@ tasks.withType { } plugins { - val kotlinVersion = "1.2.41" + val kotlinVersion = "1.2.60" id("org.jetbrains.kotlin.jvm") version kotlinVersion id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion @@ -36,7 +36,7 @@ dependencies { compile("org.jetbrains.kotlin:kotlin-reflect") compile("org.springframework.boot:spring-boot-starter-web") {{#swaggerAnnotations}} - compile("io.swagger:swagger-annotations:1.5.14") + compile("io.swagger:swagger-annotations:1.5.21") {{/swaggerAnnotations}} testCompile("org.springframework.boot:spring-boot-starter-test") { diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache deleted file mode 100644 index 3c7185bd6289..000000000000 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/defaultBasePath.mustache +++ /dev/null @@ -1 +0,0 @@ -{{contextPath}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache index 7a64ac656f9a..420eb0b9ba7f 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache @@ -6,7 +6,7 @@ {{artifactId}} {{artifactVersion}} - 1.2.41 + 1.2.60 org.springframework.boot @@ -83,7 +83,7 @@ io.swagger swagger-annotations - 1.5.14 + 1.5.21 {{/swaggerAnnotations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache index 4ab0094b4929..d83b2d0469eb 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/pathParams.mustache @@ -1 +1 @@ -{{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambdaEscapeDoubleQuote}}{{{value}}}{{/lambdaEscapeDoubleQuote}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/enumVars}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} @PathVariable("{{baseName}}") {{paramName}}: {{>optionalDataType}}{{/isPathParam}} \ No newline at end of file +{{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambda.escapeDoubleQuote}}{{{value}}}{{/lambda.escapeDoubleQuote}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/enumVars}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} @PathVariable("{{baseName}}") {{paramName}}: {{>optionalDataType}}{{/isPathParam}} \ No newline at end of file From 8192ad3f93f39f8c12babc343beab8f9f5c13311 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Mon, 20 Aug 2018 16:16:56 +0100 Subject: [PATCH 29/39] Updated samples --- .../petstore/kotlin-springboot/README.md | 21 ++++++++++++ .../kotlin-springboot/build.gradle.kts | 4 +-- .../petstore/kotlin-springboot/pom.xml | 9 +++-- .../kotlin/org/openapitools/api/PetApi.kt | 15 +++++--- .../kotlin/org/openapitools/api/StoreApi.kt | 9 +++-- .../kotlin/org/openapitools/api/UserApi.kt | 15 +++++--- .../kotlin/org/openapitools/model/Category.kt | 9 +++-- .../openapitools/model/ModelApiResponse.kt | 13 +++++-- .../kotlin/org/openapitools/model/Order.kt | 26 ++++++++++---- .../main/kotlin/org/openapitools/model/Pet.kt | 28 +++++++++++---- .../main/kotlin/org/openapitools/model/Tag.kt | 9 +++-- .../kotlin/org/openapitools/model/User.kt | 34 ++++++++++++++----- .../petstore/kotlin-springboot/README.md | 21 ++++++++++++ .../kotlin-springboot/build.gradle.kts | 4 +-- .../server/petstore/kotlin-springboot/pom.xml | 9 +++-- .../kotlin/org/openapitools/api/PetApi.kt | 15 +++++--- .../kotlin/org/openapitools/api/StoreApi.kt | 9 +++-- .../kotlin/org/openapitools/api/UserApi.kt | 15 +++++--- .../kotlin/org/openapitools/model/Category.kt | 9 +++-- .../openapitools/model/ModelApiResponse.kt | 13 +++++-- .../kotlin/org/openapitools/model/Order.kt | 26 ++++++++++---- .../main/kotlin/org/openapitools/model/Pet.kt | 28 +++++++++++---- .../main/kotlin/org/openapitools/model/Tag.kt | 9 +++-- .../kotlin/org/openapitools/model/User.kt | 34 ++++++++++++++----- 24 files changed, 292 insertions(+), 92 deletions(-) create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/README.md create mode 100644 samples/server/petstore/kotlin-springboot/README.md diff --git a/samples/server/openapi3/petstore/kotlin-springboot/README.md b/samples/server/openapi3/petstore/kotlin-springboot/README.md new file mode 100644 index 000000000000..4db0fe6ba757 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/README.md @@ -0,0 +1,21 @@ +# openAPIPetstore + +This Kotlin based [Spring Boot](https://spring.io/projects/spring-boot) application has been generated using the [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator). + +## Getting Started + +This document assumes you have either maven or gradle available, either via the wrapper or otherwise. This does not come with a gradle / maven wrapper checked in. + +By default a [`pom.xml`](pom.xml) file will be generated. If you specified `gradleBuildFile=true` when generating this project, a `build.gradle.kts` will also be generated. Note this uses [Gradle Kotlin DSL](https://github.com/gradle/kotlin-dsl). + +To build the project using maven, run: +```bash +mvn package && java -jar target/openapi-spring-1.0.0.jar +``` + +To build the project using gradle, run: +```bash +gradle build && java -jar build/libs/openapi-spring-1.0.0.jar +``` + +If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:/) diff --git a/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts b/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts index 79962e285bbf..51559950d5b0 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts +++ b/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts @@ -23,7 +23,7 @@ tasks.withType { } plugins { - val kotlinVersion = "1.2.41" + val kotlinVersion = "1.2.60" id("org.jetbrains.kotlin.jvm") version kotlinVersion id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion @@ -35,7 +35,7 @@ dependencies { compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") compile("org.jetbrains.kotlin:kotlin-reflect") compile("org.springframework.boot:spring-boot-starter-web") - compile("io.swagger:swagger-annotations:1.5.14") + compile("io.swagger:swagger-annotations:1.5.21") testCompile("org.springframework.boot:spring-boot-starter-test") { exclude(module = "junit") diff --git a/samples/server/openapi3/petstore/kotlin-springboot/pom.xml b/samples/server/openapi3/petstore/kotlin-springboot/pom.xml index 0b29122357e7..f491e5b9a571 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/pom.xml +++ b/samples/server/openapi3/petstore/kotlin-springboot/pom.xml @@ -6,7 +6,7 @@ openapi-spring 1.0.0 - 1.2.41 + 1.2.60 org.springframework.boot @@ -82,7 +82,7 @@ io.swagger swagger-annotations - 1.5.14 + 1.5.21 com.fasterxml.jackson.dataformat @@ -92,5 +92,10 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 + + + javax.validation + validation-api + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt index d7e2a4729324..05aee6becb91 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -14,14 +14,19 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.validation.annotation.Validated import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile import org.springframework.beans.factory.annotation.Autowired +import javax.validation.Valid +import javax.validation.constraints.* + import kotlin.collections.List import kotlin.collections.Map @Controller +@Validated @Api(value = "Pet", description = "The Pet API") @RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") class PetApiController(@Autowired(required = true) val service: PetApiService) { @@ -37,7 +42,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet"], consumes = ["application/json", "application/xml"], method = [RequestMethod.POST]) - fun addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + fun addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @Valid @RequestBody pet: Pet): ResponseEntity { return ResponseEntity(service.addPet(pet), HttpStatus.OK) } @@ -68,7 +73,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet/findByStatus"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun findPetsByStatus(@ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @RequestParam(value = "status", required = true) status: kotlin.Array): ResponseEntity> { + fun findPetsByStatus(@NotNull @ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @Valid @RequestParam(value = "status", required = true) status: kotlin.Array): ResponseEntity> { return ResponseEntity(service.findPetsByStatus(status), HttpStatus.OK) } @@ -85,7 +90,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet/findByTags"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun findPetsByTags(@ApiParam(value = "Tags to filter by", required = true) @RequestParam(value = "tags", required = true) tags: kotlin.Array): ResponseEntity> { + fun findPetsByTags(@NotNull @ApiParam(value = "Tags to filter by", required = true) @Valid @RequestParam(value = "tags", required = true) tags: kotlin.Array): ResponseEntity> { return ResponseEntity(service.findPetsByTags(tags), HttpStatus.OK) } @@ -116,7 +121,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet"], consumes = ["application/json", "application/xml"], method = [RequestMethod.PUT]) - fun updatePet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + fun updatePet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @Valid @RequestBody pet: Pet): ResponseEntity { return ResponseEntity(service.updatePet(pet), HttpStatus.OK) } @@ -148,7 +153,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { produces = ["application/json"], consumes = ["multipart/form-data"], method = [RequestMethod.POST]) - fun uploadFile(@ApiParam(value = "ID of pet to update", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Additional data to pass to server", defaultValue="null") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: kotlin.String ,@ApiParam(value = "file detail") @RequestPart("file") file: MultipartFile): ResponseEntity { + fun uploadFile(@ApiParam(value = "ID of pet to update", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Additional data to pass to server", defaultValue="null") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: kotlin.String ,@ApiParam(value = "file detail") @Valid @RequestPart("file") file: MultipartFile): ResponseEntity { return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK) } } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt index 7c272813412f..fb6c7cb9a326 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt @@ -13,14 +13,19 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.validation.annotation.Validated import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile import org.springframework.beans.factory.annotation.Autowired +import javax.validation.Valid +import javax.validation.constraints.* + import kotlin.collections.List import kotlin.collections.Map @Controller +@Validated @Api(value = "Store", description = "The Store API") @RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") class StoreApiController(@Autowired(required = true) val service: StoreApiService) { @@ -66,7 +71,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic value = ["/store/order/{orderId}"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun getOrderById(@ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity { + fun getOrderById(@Min(1L) @Max(5L) @ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity { return ResponseEntity(service.getOrderById(orderId), HttpStatus.OK) } @@ -82,7 +87,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic produces = ["application/xml", "application/json"], consumes = ["application/json"], method = [RequestMethod.POST]) - fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @RequestBody order: Order): ResponseEntity { + fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @Valid @RequestBody order: Order): ResponseEntity { return ResponseEntity(service.placeOrder(order), HttpStatus.OK) } } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt index feb69360819a..4b88b867b131 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt @@ -13,14 +13,19 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.validation.annotation.Validated import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile import org.springframework.beans.factory.annotation.Autowired +import javax.validation.Valid +import javax.validation.constraints.* + import kotlin.collections.List import kotlin.collections.Map @Controller +@Validated @Api(value = "User", description = "The User API") @RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") class UserApiController(@Autowired(required = true) val service: UserApiService) { @@ -35,7 +40,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) value = ["/user"], consumes = ["application/json"], method = [RequestMethod.POST]) - fun createUser(@ApiParam(value = "Created user object" ,required=true ) @RequestBody user: User): ResponseEntity { + fun createUser(@ApiParam(value = "Created user object" ,required=true ) @Valid @RequestBody user: User): ResponseEntity { return ResponseEntity(service.createUser(user), HttpStatus.OK) } @@ -49,7 +54,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) value = ["/user/createWithArray"], consumes = ["application/json"], method = [RequestMethod.POST]) - fun createUsersWithArrayInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + fun createUsersWithArrayInput(@ApiParam(value = "List of user object" ,required=true ) @Valid @RequestBody user: kotlin.Array): ResponseEntity { return ResponseEntity(service.createUsersWithArrayInput(user), HttpStatus.OK) } @@ -63,7 +68,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) value = ["/user/createWithList"], consumes = ["application/json"], method = [RequestMethod.POST]) - fun createUsersWithListInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + fun createUsersWithListInput(@ApiParam(value = "List of user object" ,required=true ) @Valid @RequestBody user: kotlin.Array): ResponseEntity { return ResponseEntity(service.createUsersWithListInput(user), HttpStatus.OK) } @@ -106,7 +111,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) value = ["/user/login"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun loginUser(@ApiParam(value = "The user name for login", required = true) @RequestParam(value = "username", required = true) username: kotlin.String,@ApiParam(value = "The password for login in clear text", required = true) @RequestParam(value = "password", required = true) password: kotlin.String): ResponseEntity { + fun loginUser(@NotNull @ApiParam(value = "The user name for login", required = true) @Valid @RequestParam(value = "username", required = true) username: kotlin.String,@NotNull @ApiParam(value = "The password for login in clear text", required = true) @Valid @RequestParam(value = "password", required = true) password: kotlin.String): ResponseEntity { return ResponseEntity(service.loginUser(username, password), HttpStatus.OK) } @@ -133,7 +138,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) value = ["/user/{username}"], consumes = ["application/json"], method = [RequestMethod.PUT]) - fun updateUser(@ApiParam(value = "name that need to be deleted", required=true) @PathVariable("username") username: kotlin.String,@ApiParam(value = "Updated user object" ,required=true ) @RequestBody user: User): ResponseEntity { + fun updateUser(@ApiParam(value = "name that need to be deleted", required=true) @PathVariable("username") username: kotlin.String,@ApiParam(value = "Updated user object" ,required=true ) @Valid @RequestBody user: User): ResponseEntity { return ResponseEntity(service.updateUser(username, user), HttpStatus.OK) } } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt index d37545dc03be..36d48aa09384 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A category for a pet @@ -11,8 +12,12 @@ import javax.validation.constraints.* * @param name */ data class Category ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("name") val name: kotlin.String? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("name") val name: kotlin.String? = null ) { } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt index 0ac2323e8dd0..9a259e9baa24 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * Describes the result of uploading an image resource @@ -12,9 +13,15 @@ import javax.validation.constraints.* * @param message */ data class ModelApiResponse ( - @JsonProperty("code") val code: kotlin.Int? = null, - @JsonProperty("type") val type: kotlin.String? = null, - @JsonProperty("message") val message: kotlin.String? = null + + @ApiModelProperty(value = "") + @JsonProperty("code") val code: kotlin.Int? = null, + + @ApiModelProperty(value = "") + @JsonProperty("type") val type: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("message") val message: kotlin.String? = null ) { } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index 5d8e3d60e858..c6036825d371 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonValue import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * An order for a pets from the pet store @@ -16,13 +17,24 @@ import javax.validation.constraints.* * @param complete */ data class Order ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("petId") val petId: kotlin.Long? = null, - @JsonProperty("quantity") val quantity: kotlin.Int? = null, - @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, - /* Order Status */ - @JsonProperty("status") val status: Order.Status? = null, - @JsonProperty("complete") val complete: kotlin.Boolean? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("petId") val petId: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("quantity") val quantity: kotlin.Int? = null, + + @ApiModelProperty(value = "") + @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + + @ApiModelProperty(value = "Order Status") + @JsonProperty("status") val status: Order.Status? = null, + + @ApiModelProperty(value = "") + @JsonProperty("complete") val complete: kotlin.Boolean? = null ) { /** diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt index 829a70a238a6..29665f17797d 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt @@ -7,6 +7,7 @@ import org.openapitools.model.Category import org.openapitools.model.Tag import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A pet for sale in the pet store @@ -18,13 +19,26 @@ import javax.validation.constraints.* * @param status pet status in the store */ data class Pet ( - @JsonProperty("name") val name: kotlin.String, - @JsonProperty("photoUrls") val photoUrls: kotlin.Array, - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("category") val category: Category? = null, - @JsonProperty("tags") val tags: kotlin.Array? = null, - /* pet status in the store */ - @JsonProperty("status") val status: Pet.Status? = null + + @get:NotNull + @ApiModelProperty(example = "doggie", required = true, value = "") + @JsonProperty("name") val name: kotlin.String, + + @get:NotNull + @ApiModelProperty(required = true, value = "") + @JsonProperty("photoUrls") val photoUrls: kotlin.Array, + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("category") val category: Category? = null, + + @ApiModelProperty(value = "") + @JsonProperty("tags") val tags: kotlin.Array? = null, + + @ApiModelProperty(value = "pet status in the store") + @JsonProperty("status") val status: Pet.Status? = null ) { /** diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt index 4c409816464a..76b362380bf6 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A tag for a pet @@ -11,8 +12,12 @@ import javax.validation.constraints.* * @param name */ data class Tag ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("name") val name: kotlin.String? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("name") val name: kotlin.String? = null ) { } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt index 4e7e729b2639..6ebdab0208c8 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A User who is purchasing from the pet store @@ -17,15 +18,30 @@ import javax.validation.constraints.* * @param userStatus User Status */ data class User ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("username") val username: kotlin.String? = null, - @JsonProperty("firstName") val firstName: kotlin.String? = null, - @JsonProperty("lastName") val lastName: kotlin.String? = null, - @JsonProperty("email") val email: kotlin.String? = null, - @JsonProperty("password") val password: kotlin.String? = null, - @JsonProperty("phone") val phone: kotlin.String? = null, - /* User Status */ - @JsonProperty("userStatus") val userStatus: kotlin.Int? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("username") val username: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("firstName") val firstName: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("lastName") val lastName: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("email") val email: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("password") val password: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("phone") val phone: kotlin.String? = null, + + @ApiModelProperty(value = "User Status") + @JsonProperty("userStatus") val userStatus: kotlin.Int? = null ) { } diff --git a/samples/server/petstore/kotlin-springboot/README.md b/samples/server/petstore/kotlin-springboot/README.md new file mode 100644 index 000000000000..4db0fe6ba757 --- /dev/null +++ b/samples/server/petstore/kotlin-springboot/README.md @@ -0,0 +1,21 @@ +# openAPIPetstore + +This Kotlin based [Spring Boot](https://spring.io/projects/spring-boot) application has been generated using the [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator). + +## Getting Started + +This document assumes you have either maven or gradle available, either via the wrapper or otherwise. This does not come with a gradle / maven wrapper checked in. + +By default a [`pom.xml`](pom.xml) file will be generated. If you specified `gradleBuildFile=true` when generating this project, a `build.gradle.kts` will also be generated. Note this uses [Gradle Kotlin DSL](https://github.com/gradle/kotlin-dsl). + +To build the project using maven, run: +```bash +mvn package && java -jar target/openapi-spring-1.0.0.jar +``` + +To build the project using gradle, run: +```bash +gradle build && java -jar build/libs/openapi-spring-1.0.0.jar +``` + +If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:/) diff --git a/samples/server/petstore/kotlin-springboot/build.gradle.kts b/samples/server/petstore/kotlin-springboot/build.gradle.kts index 79962e285bbf..51559950d5b0 100644 --- a/samples/server/petstore/kotlin-springboot/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot/build.gradle.kts @@ -23,7 +23,7 @@ tasks.withType { } plugins { - val kotlinVersion = "1.2.41" + val kotlinVersion = "1.2.60" id("org.jetbrains.kotlin.jvm") version kotlinVersion id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion @@ -35,7 +35,7 @@ dependencies { compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") compile("org.jetbrains.kotlin:kotlin-reflect") compile("org.springframework.boot:spring-boot-starter-web") - compile("io.swagger:swagger-annotations:1.5.14") + compile("io.swagger:swagger-annotations:1.5.21") testCompile("org.springframework.boot:spring-boot-starter-test") { exclude(module = "junit") diff --git a/samples/server/petstore/kotlin-springboot/pom.xml b/samples/server/petstore/kotlin-springboot/pom.xml index 0b29122357e7..f491e5b9a571 100644 --- a/samples/server/petstore/kotlin-springboot/pom.xml +++ b/samples/server/petstore/kotlin-springboot/pom.xml @@ -6,7 +6,7 @@ openapi-spring 1.0.0 - 1.2.41 + 1.2.60 org.springframework.boot @@ -82,7 +82,7 @@ io.swagger swagger-annotations - 1.5.14 + 1.5.21 com.fasterxml.jackson.dataformat @@ -92,5 +92,10 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 + + + javax.validation + validation-api + diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt index d7e2a4729324..05aee6becb91 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -14,14 +14,19 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.validation.annotation.Validated import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile import org.springframework.beans.factory.annotation.Autowired +import javax.validation.Valid +import javax.validation.constraints.* + import kotlin.collections.List import kotlin.collections.Map @Controller +@Validated @Api(value = "Pet", description = "The Pet API") @RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") class PetApiController(@Autowired(required = true) val service: PetApiService) { @@ -37,7 +42,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet"], consumes = ["application/json", "application/xml"], method = [RequestMethod.POST]) - fun addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + fun addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @Valid @RequestBody pet: Pet): ResponseEntity { return ResponseEntity(service.addPet(pet), HttpStatus.OK) } @@ -68,7 +73,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet/findByStatus"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun findPetsByStatus(@ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @RequestParam(value = "status", required = true) status: kotlin.Array): ResponseEntity> { + fun findPetsByStatus(@NotNull @ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @Valid @RequestParam(value = "status", required = true) status: kotlin.Array): ResponseEntity> { return ResponseEntity(service.findPetsByStatus(status), HttpStatus.OK) } @@ -85,7 +90,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet/findByTags"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun findPetsByTags(@ApiParam(value = "Tags to filter by", required = true) @RequestParam(value = "tags", required = true) tags: kotlin.Array): ResponseEntity> { + fun findPetsByTags(@NotNull @ApiParam(value = "Tags to filter by", required = true) @Valid @RequestParam(value = "tags", required = true) tags: kotlin.Array): ResponseEntity> { return ResponseEntity(service.findPetsByTags(tags), HttpStatus.OK) } @@ -116,7 +121,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { value = ["/pet"], consumes = ["application/json", "application/xml"], method = [RequestMethod.PUT]) - fun updatePet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody pet: Pet): ResponseEntity { + fun updatePet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @Valid @RequestBody pet: Pet): ResponseEntity { return ResponseEntity(service.updatePet(pet), HttpStatus.OK) } @@ -148,7 +153,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) { produces = ["application/json"], consumes = ["multipart/form-data"], method = [RequestMethod.POST]) - fun uploadFile(@ApiParam(value = "ID of pet to update", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Additional data to pass to server", defaultValue="null") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: kotlin.String ,@ApiParam(value = "file detail") @RequestPart("file") file: MultipartFile): ResponseEntity { + fun uploadFile(@ApiParam(value = "ID of pet to update", required=true) @PathVariable("petId") petId: kotlin.Long,@ApiParam(value = "Additional data to pass to server", defaultValue="null") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: kotlin.String ,@ApiParam(value = "file detail") @Valid @RequestPart("file") file: MultipartFile): ResponseEntity { return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK) } } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt index db13ad07f700..fd682adb7c29 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/StoreApi.kt @@ -13,14 +13,19 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.validation.annotation.Validated import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile import org.springframework.beans.factory.annotation.Autowired +import javax.validation.Valid +import javax.validation.constraints.* + import kotlin.collections.List import kotlin.collections.Map @Controller +@Validated @Api(value = "Store", description = "The Store API") @RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") class StoreApiController(@Autowired(required = true) val service: StoreApiService) { @@ -66,7 +71,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic value = ["/store/order/{orderId}"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun getOrderById(@ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity { + fun getOrderById(@Min(1L) @Max(5L) @ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity { return ResponseEntity(service.getOrderById(orderId), HttpStatus.OK) } @@ -81,7 +86,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic value = ["/store/order"], produces = ["application/xml", "application/json"], method = [RequestMethod.POST]) - fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @RequestBody order: Order): ResponseEntity { + fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @Valid @RequestBody order: Order): ResponseEntity { return ResponseEntity(service.placeOrder(order), HttpStatus.OK) } } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt index 6b8e13f04ced..cc275f82f4c9 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/UserApi.kt @@ -13,14 +13,19 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.validation.annotation.Validated import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.multipart.MultipartFile import org.springframework.beans.factory.annotation.Autowired +import javax.validation.Valid +import javax.validation.constraints.* + import kotlin.collections.List import kotlin.collections.Map @Controller +@Validated @Api(value = "User", description = "The User API") @RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}") class UserApiController(@Autowired(required = true) val service: UserApiService) { @@ -34,7 +39,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) @RequestMapping( value = ["/user"], method = [RequestMethod.POST]) - fun createUser(@ApiParam(value = "Created user object" ,required=true ) @RequestBody user: User): ResponseEntity { + fun createUser(@ApiParam(value = "Created user object" ,required=true ) @Valid @RequestBody user: User): ResponseEntity { return ResponseEntity(service.createUser(user), HttpStatus.OK) } @@ -47,7 +52,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) @RequestMapping( value = ["/user/createWithArray"], method = [RequestMethod.POST]) - fun createUsersWithArrayInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + fun createUsersWithArrayInput(@ApiParam(value = "List of user object" ,required=true ) @Valid @RequestBody user: kotlin.Array): ResponseEntity { return ResponseEntity(service.createUsersWithArrayInput(user), HttpStatus.OK) } @@ -60,7 +65,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) @RequestMapping( value = ["/user/createWithList"], method = [RequestMethod.POST]) - fun createUsersWithListInput(@ApiParam(value = "List of user object" ,required=true ) @RequestBody user: kotlin.Array): ResponseEntity { + fun createUsersWithListInput(@ApiParam(value = "List of user object" ,required=true ) @Valid @RequestBody user: kotlin.Array): ResponseEntity { return ResponseEntity(service.createUsersWithListInput(user), HttpStatus.OK) } @@ -103,7 +108,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) value = ["/user/login"], produces = ["application/xml", "application/json"], method = [RequestMethod.GET]) - fun loginUser(@ApiParam(value = "The user name for login", required = true) @RequestParam(value = "username", required = true) username: kotlin.String,@ApiParam(value = "The password for login in clear text", required = true) @RequestParam(value = "password", required = true) password: kotlin.String): ResponseEntity { + fun loginUser(@NotNull @ApiParam(value = "The user name for login", required = true) @Valid @RequestParam(value = "username", required = true) username: kotlin.String,@NotNull @ApiParam(value = "The password for login in clear text", required = true) @Valid @RequestParam(value = "password", required = true) password: kotlin.String): ResponseEntity { return ResponseEntity(service.loginUser(username, password), HttpStatus.OK) } @@ -129,7 +134,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService) @RequestMapping( value = ["/user/{username}"], method = [RequestMethod.PUT]) - fun updateUser(@ApiParam(value = "name that need to be deleted", required=true) @PathVariable("username") username: kotlin.String,@ApiParam(value = "Updated user object" ,required=true ) @RequestBody user: User): ResponseEntity { + fun updateUser(@ApiParam(value = "name that need to be deleted", required=true) @PathVariable("username") username: kotlin.String,@ApiParam(value = "Updated user object" ,required=true ) @Valid @RequestBody user: User): ResponseEntity { return ResponseEntity(service.updateUser(username, user), HttpStatus.OK) } } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt index d37545dc03be..36d48aa09384 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Category.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A category for a pet @@ -11,8 +12,12 @@ import javax.validation.constraints.* * @param name */ data class Category ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("name") val name: kotlin.String? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("name") val name: kotlin.String? = null ) { } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt index 0ac2323e8dd0..9a259e9baa24 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/ModelApiResponse.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * Describes the result of uploading an image resource @@ -12,9 +13,15 @@ import javax.validation.constraints.* * @param message */ data class ModelApiResponse ( - @JsonProperty("code") val code: kotlin.Int? = null, - @JsonProperty("type") val type: kotlin.String? = null, - @JsonProperty("message") val message: kotlin.String? = null + + @ApiModelProperty(value = "") + @JsonProperty("code") val code: kotlin.Int? = null, + + @ApiModelProperty(value = "") + @JsonProperty("type") val type: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("message") val message: kotlin.String? = null ) { } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index 5d8e3d60e858..c6036825d371 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonValue import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * An order for a pets from the pet store @@ -16,13 +17,24 @@ import javax.validation.constraints.* * @param complete */ data class Order ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("petId") val petId: kotlin.Long? = null, - @JsonProperty("quantity") val quantity: kotlin.Int? = null, - @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, - /* Order Status */ - @JsonProperty("status") val status: Order.Status? = null, - @JsonProperty("complete") val complete: kotlin.Boolean? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("petId") val petId: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("quantity") val quantity: kotlin.Int? = null, + + @ApiModelProperty(value = "") + @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + + @ApiModelProperty(value = "Order Status") + @JsonProperty("status") val status: Order.Status? = null, + + @ApiModelProperty(value = "") + @JsonProperty("complete") val complete: kotlin.Boolean? = null ) { /** diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt index 829a70a238a6..29665f17797d 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Pet.kt @@ -7,6 +7,7 @@ import org.openapitools.model.Category import org.openapitools.model.Tag import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A pet for sale in the pet store @@ -18,13 +19,26 @@ import javax.validation.constraints.* * @param status pet status in the store */ data class Pet ( - @JsonProperty("name") val name: kotlin.String, - @JsonProperty("photoUrls") val photoUrls: kotlin.Array, - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("category") val category: Category? = null, - @JsonProperty("tags") val tags: kotlin.Array? = null, - /* pet status in the store */ - @JsonProperty("status") val status: Pet.Status? = null + + @get:NotNull + @ApiModelProperty(example = "doggie", required = true, value = "") + @JsonProperty("name") val name: kotlin.String, + + @get:NotNull + @ApiModelProperty(required = true, value = "") + @JsonProperty("photoUrls") val photoUrls: kotlin.Array, + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("category") val category: Category? = null, + + @ApiModelProperty(value = "") + @JsonProperty("tags") val tags: kotlin.Array? = null, + + @ApiModelProperty(value = "pet status in the store") + @JsonProperty("status") val status: Pet.Status? = null ) { /** diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt index 4c409816464a..76b362380bf6 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Tag.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A tag for a pet @@ -11,8 +12,12 @@ import javax.validation.constraints.* * @param name */ data class Tag ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("name") val name: kotlin.String? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("name") val name: kotlin.String? = null ) { } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt index 4e7e729b2639..6ebdab0208c8 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/User.kt @@ -4,6 +4,7 @@ import java.util.Objects import com.fasterxml.jackson.annotation.JsonProperty import javax.validation.Valid import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty /** * A User who is purchasing from the pet store @@ -17,15 +18,30 @@ import javax.validation.constraints.* * @param userStatus User Status */ data class User ( - @JsonProperty("id") val id: kotlin.Long? = null, - @JsonProperty("username") val username: kotlin.String? = null, - @JsonProperty("firstName") val firstName: kotlin.String? = null, - @JsonProperty("lastName") val lastName: kotlin.String? = null, - @JsonProperty("email") val email: kotlin.String? = null, - @JsonProperty("password") val password: kotlin.String? = null, - @JsonProperty("phone") val phone: kotlin.String? = null, - /* User Status */ - @JsonProperty("userStatus") val userStatus: kotlin.Int? = null + + @ApiModelProperty(value = "") + @JsonProperty("id") val id: kotlin.Long? = null, + + @ApiModelProperty(value = "") + @JsonProperty("username") val username: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("firstName") val firstName: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("lastName") val lastName: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("email") val email: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("password") val password: kotlin.String? = null, + + @ApiModelProperty(value = "") + @JsonProperty("phone") val phone: kotlin.String? = null, + + @ApiModelProperty(value = "User Status") + @JsonProperty("userStatus") val userStatus: kotlin.Int? = null ) { } From d8d35860d8b9360bf75c61f090599dc40d1a79a1 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Mon, 20 Aug 2018 17:43:26 +0100 Subject: [PATCH 30/39] Generating ConstraintViolation Exception Handler, as Springboot doesnt correctly catch the error and return bad request. Handling other exceptions a litle better --- .../kotlin-spring/exceptions.mustache | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache index 8aa816faefab..d85b8396fa5f 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/exceptions.mustache @@ -1,11 +1,12 @@ package {{apiPackage}} import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import javax.validation.ConstraintViolationException +// TODO Extend ApiException for custom exception handling, e.g. the below NotFound exception sealed class ApiException(msg: String, val code: Int) : Exception(msg) class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) @@ -14,11 +15,15 @@ class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : @ControllerAdvice class DefaultExceptionHandler { - @ExceptionHandler(value = [NotFoundException::class]) - fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.valueOf(ex.code)) + @ExceptionHandler(value = [ApiException::class]) + fun onApiException(ex: ApiException, response: HttpServletResponse): Unit = + response.sendError(ex.code, ex.message) @ExceptionHandler(value = [NotImplementedError::class]) - fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.NOT_IMPLEMENTED) + fun onNotImplemented(ex: NotImplementedError, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.NOT_IMPLEMENTED.value()) + + @ExceptionHandler(value = [ConstraintViolationException::class]) + fun onConstraintViolation(ex: ConstraintViolationException, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.BAD_REQUEST.value(), ex.constraintViolations.joinToString(", ") { it.message }) } From d673abae7401122bf9156a82ca2c91afc293aefd Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 21 Aug 2018 12:06:07 +0100 Subject: [PATCH 31/39] Small fix for date time mappings (plus sample re-gen) --- .../languages/AbstractKotlinCodegen.java | 10 ++++------ .../kotlin/KotlinClientCodegenModelTest.java | 8 ++++---- samples/client/petstore/kotlin/docs/Order.md | 2 +- .../org/openapitools/client/models/Order.kt | 2 +- .../kotlin/org/openapitools/api/Exceptions.kt | 19 ++++++++++++------- .../kotlin/org/openapitools/model/Order.kt | 2 +- .../kotlin/org/openapitools/api/Exceptions.kt | 19 ++++++++++++------- .../kotlin/org/openapitools/model/Order.kt | 2 +- 8 files changed, 36 insertions(+), 28 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index 4055f99bad9b..87f3afc9ecd7 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -160,16 +160,14 @@ public AbstractKotlinCodegen() { typeMapping.put("double", "kotlin.Double"); typeMapping.put("ByteArray", "kotlin.ByteArray"); typeMapping.put("number", "java.math.BigDecimal"); - typeMapping.put("date-time", "java.time.LocalDateTime"); - typeMapping.put("date", "java.time.LocalDateTime"); + typeMapping.put("date-time", "java.time.OffsetDateTime"); + typeMapping.put("date", "java.time.LocalDate"); typeMapping.put("file", "java.io.File"); typeMapping.put("array", "kotlin.Array"); typeMapping.put("list", "kotlin.collections.List"); typeMapping.put("map", "kotlin.collections.Map"); typeMapping.put("object", "kotlin.Any"); typeMapping.put("binary", "kotlin.Array"); - typeMapping.put("Date", "java.time.LocalDateTime"); - typeMapping.put("DateTime", "java.time.LocalDateTime"); instantiationTypes.put("array", "kotlin.arrayOf"); instantiationTypes.put("list", "kotlin.arrayOf"); @@ -179,9 +177,9 @@ public AbstractKotlinCodegen() { importMapping.put("BigDecimal", "java.math.BigDecimal"); importMapping.put("UUID", "java.util.UUID"); importMapping.put("File", "java.io.File"); - importMapping.put("Date", "java.util.Date"); importMapping.put("Timestamp", "java.sql.Timestamp"); - importMapping.put("DateTime", "java.time.LocalDateTime"); + importMapping.put("Date", "java.time.LocalDate"); + importMapping.put("DateTime", "java.time.OffsetDateTime"); importMapping.put("LocalDateTime", "java.time.LocalDateTime"); importMapping.put("LocalDate", "java.time.LocalDate"); importMapping.put("LocalTime", "java.time.LocalTime"); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java index 312a2fa32e3e..4685eae91949 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java @@ -105,10 +105,10 @@ public void simpleModelTest() { final CodegenProperty property3 = cm.vars.get(2); Assert.assertEquals(property3.baseName, "createdAt"); - Assert.assertEquals(property3.dataType, "java.time.LocalDateTime"); + Assert.assertEquals(property3.dataType, "java.time.OffsetDateTime"); Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); - Assert.assertEquals(property3.baseType, "java.time.LocalDateTime"); + Assert.assertEquals(property3.baseType, "java.time.OffsetDateTime"); Assert.assertFalse(property3.hasMore); Assert.assertFalse(property3.required); Assert.assertTrue(property3.isNotContainer); @@ -165,10 +165,10 @@ public void selectDateLibraryAsJava8() { final CodegenProperty property3 = cm.vars.get(2); Assert.assertEquals(property3.baseName, "createdAt"); - Assert.assertEquals(property3.dataType, "java.time.LocalDateTime"); + Assert.assertEquals(property3.dataType, "java.time.OffsetDateTime"); Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); - Assert.assertEquals(property3.baseType, "java.time.LocalDateTime"); + Assert.assertEquals(property3.baseType, "java.time.OffsetDateTime"); Assert.assertFalse(property3.hasMore); Assert.assertFalse(property3.required); Assert.assertTrue(property3.isNotContainer); diff --git a/samples/client/petstore/kotlin/docs/Order.md b/samples/client/petstore/kotlin/docs/Order.md index ef31dbf2f4f4..5112f08958d5 100644 --- a/samples/client/petstore/kotlin/docs/Order.md +++ b/samples/client/petstore/kotlin/docs/Order.md @@ -7,7 +7,7 @@ Name | Type | Description | Notes **id** | **kotlin.Long** | | [optional] **petId** | **kotlin.Long** | | [optional] **quantity** | **kotlin.Int** | | [optional] -**shipDate** | [**java.time.LocalDateTime**](java.time.LocalDateTime.md) | | [optional] +**shipDate** | [**java.time.OffsetDateTime**](java.time.OffsetDateTime.md) | | [optional] **status** | [**inline**](#StatusEnum) | Order Status | [optional] **complete** | **kotlin.Boolean** | | [optional] diff --git a/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt b/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt index 44a8b1f896c4..0a163169bef1 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt @@ -26,7 +26,7 @@ data class Order ( val id: kotlin.Long? = null, val petId: kotlin.Long? = null, val quantity: kotlin.Int? = null, - val shipDate: java.time.LocalDateTime? = null, + val shipDate: java.time.OffsetDateTime? = null, /* Order Status */ val status: Order.Status? = null, val complete: kotlin.Boolean? = null diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt index afba2986af28..4d8400902aa9 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -1,11 +1,12 @@ package org.openapitools.api import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import javax.validation.ConstraintViolationException +// TODO Extend ApiException for custom exception handling, e.g. the below NotFound exception sealed class ApiException(msg: String, val code: Int) : Exception(msg) class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) @@ -14,11 +15,15 @@ class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : @ControllerAdvice class DefaultExceptionHandler { - @ExceptionHandler(value = [NotFoundException::class]) - fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.valueOf(ex.code)) + @ExceptionHandler(value = [ApiException::class]) + fun onApiException(ex: ApiException, response: HttpServletResponse): Unit = + response.sendError(ex.code, ex.message) @ExceptionHandler(value = [NotImplementedError::class]) - fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.NOT_IMPLEMENTED) + fun onNotImplemented(ex: NotImplementedError, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.NOT_IMPLEMENTED.value()) + + @ExceptionHandler(value = [ConstraintViolationException::class]) + fun onConstraintViolation(ex: ConstraintViolationException, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.BAD_REQUEST.value(), ex.constraintViolations.joinToString(", ") { it.message }) } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index c6036825d371..2a7a639a9cfc 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -28,7 +28,7 @@ data class Order ( @JsonProperty("quantity") val quantity: kotlin.Int? = null, @ApiModelProperty(value = "") - @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + @JsonProperty("shipDate") val shipDate: java.time.OffsetDateTime? = null, @ApiModelProperty(value = "Order Status") @JsonProperty("status") val status: Order.Status? = null, diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt index afba2986af28..4d8400902aa9 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -1,11 +1,12 @@ package org.openapitools.api import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import javax.validation.ConstraintViolationException +// TODO Extend ApiException for custom exception handling, e.g. the below NotFound exception sealed class ApiException(msg: String, val code: Int) : Exception(msg) class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) @@ -14,11 +15,15 @@ class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : @ControllerAdvice class DefaultExceptionHandler { - @ExceptionHandler(value = [NotFoundException::class]) - fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.valueOf(ex.code)) + @ExceptionHandler(value = [ApiException::class]) + fun onApiException(ex: ApiException, response: HttpServletResponse): Unit = + response.sendError(ex.code, ex.message) @ExceptionHandler(value = [NotImplementedError::class]) - fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.NOT_IMPLEMENTED) + fun onNotImplemented(ex: NotImplementedError, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.NOT_IMPLEMENTED.value()) + + @ExceptionHandler(value = [ConstraintViolationException::class]) + fun onConstraintViolation(ex: ConstraintViolationException, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.BAD_REQUEST.value(), ex.constraintViolations.joinToString(", ") { it.message }) } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index c6036825d371..2a7a639a9cfc 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -28,7 +28,7 @@ data class Order ( @JsonProperty("quantity") val quantity: kotlin.Int? = null, @ApiModelProperty(value = "") - @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + @JsonProperty("shipDate") val shipDate: java.time.OffsetDateTime? = null, @ApiModelProperty(value = "Order Status") @JsonProperty("status") val status: Order.Status? = null, From 9b7d5c576d3cb3e8756156d1d5f562207264c5a0 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 21 Aug 2018 13:32:00 +0100 Subject: [PATCH 32/39] Minor fix in README template, where port was using wrong variable --- .../kotlin-spring/libraries/spring-boot/README.mustache | 2 +- samples/server/openapi3/petstore/kotlin-springboot/README.md | 2 +- samples/server/petstore/kotlin-springboot/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache index 9c347d4db0fe..c25481e376bb 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/README.mustache @@ -18,4 +18,4 @@ To build the project using gradle, run: gradle build && java -jar build/libs/{{artifactId}}-{{artifactVersion}}.jar ``` -If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:{{port}}/) +If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:{{serverPort}}/) diff --git a/samples/server/openapi3/petstore/kotlin-springboot/README.md b/samples/server/openapi3/petstore/kotlin-springboot/README.md index 4db0fe6ba757..b6865a081135 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/README.md +++ b/samples/server/openapi3/petstore/kotlin-springboot/README.md @@ -18,4 +18,4 @@ To build the project using gradle, run: gradle build && java -jar build/libs/openapi-spring-1.0.0.jar ``` -If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:/) +If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:8080/) diff --git a/samples/server/petstore/kotlin-springboot/README.md b/samples/server/petstore/kotlin-springboot/README.md index 4db0fe6ba757..b6865a081135 100644 --- a/samples/server/petstore/kotlin-springboot/README.md +++ b/samples/server/petstore/kotlin-springboot/README.md @@ -18,4 +18,4 @@ To build the project using gradle, run: gradle build && java -jar build/libs/openapi-spring-1.0.0.jar ``` -If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:/) +If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:8080/) From 61ceff38e2796f7cc72cf645a9bad41867badc5c Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 21 Aug 2018 14:30:53 +0100 Subject: [PATCH 33/39] Fix missing jackson-dataformat-xml dependency --- .../libraries/spring-boot/buildGradleKts.mustache | 2 ++ .../kotlin-spring/libraries/spring-boot/pom.mustache | 4 ++++ .../openapi3/petstore/kotlin-springboot/build.gradle.kts | 2 ++ samples/server/openapi3/petstore/kotlin-springboot/pom.xml | 4 ++++ samples/server/petstore/kotlin-springboot/build.gradle.kts | 2 ++ samples/server/petstore/kotlin-springboot/pom.xml | 4 ++++ 6 files changed, 18 insertions(+) diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache index e4d6aa6d365a..d8c488429f93 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache @@ -38,6 +38,8 @@ dependencies { {{#swaggerAnnotations}} compile("io.swagger:swagger-annotations:1.5.21") {{/swaggerAnnotations}} + compile("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml") + compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") testCompile("org.springframework.boot:spring-boot-starter-test") { exclude(module = "junit") diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache index 420eb0b9ba7f..fe2c87baaefe 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache @@ -90,6 +90,10 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + com.fasterxml.jackson.datatype jackson-datatype-jsr310 diff --git a/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts b/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts index 51559950d5b0..b5a8fef7453b 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts +++ b/samples/server/openapi3/petstore/kotlin-springboot/build.gradle.kts @@ -36,6 +36,8 @@ dependencies { compile("org.jetbrains.kotlin:kotlin-reflect") compile("org.springframework.boot:spring-boot-starter-web") compile("io.swagger:swagger-annotations:1.5.21") + compile("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml") + compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") testCompile("org.springframework.boot:spring-boot-starter-test") { exclude(module = "junit") diff --git a/samples/server/openapi3/petstore/kotlin-springboot/pom.xml b/samples/server/openapi3/petstore/kotlin-springboot/pom.xml index f491e5b9a571..fb79c82ccaec 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/pom.xml +++ b/samples/server/openapi3/petstore/kotlin-springboot/pom.xml @@ -88,6 +88,10 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + com.fasterxml.jackson.datatype jackson-datatype-jsr310 diff --git a/samples/server/petstore/kotlin-springboot/build.gradle.kts b/samples/server/petstore/kotlin-springboot/build.gradle.kts index 51559950d5b0..b5a8fef7453b 100644 --- a/samples/server/petstore/kotlin-springboot/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot/build.gradle.kts @@ -36,6 +36,8 @@ dependencies { compile("org.jetbrains.kotlin:kotlin-reflect") compile("org.springframework.boot:spring-boot-starter-web") compile("io.swagger:swagger-annotations:1.5.21") + compile("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml") + compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") testCompile("org.springframework.boot:spring-boot-starter-test") { exclude(module = "junit") diff --git a/samples/server/petstore/kotlin-springboot/pom.xml b/samples/server/petstore/kotlin-springboot/pom.xml index f491e5b9a571..fb79c82ccaec 100644 --- a/samples/server/petstore/kotlin-springboot/pom.xml +++ b/samples/server/petstore/kotlin-springboot/pom.xml @@ -88,6 +88,10 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + com.fasterxml.jackson.datatype jackson-datatype-jsr310 From dd22c9066f80d43871284a7bd39b3db3dc922617 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Tue, 21 Aug 2018 15:17:09 +0100 Subject: [PATCH 34/39] Fix build - needed to re-run kotlin-server-petstore.sh --- .../src/main/kotlin/org/openapitools/server/models/Order.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt index 3ec31bfc714f..2eb4fe92bd28 100644 --- a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt +++ b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt @@ -25,7 +25,7 @@ data class Order ( val id: kotlin.Long? = null, val petId: kotlin.Long? = null, val quantity: kotlin.Int? = null, - val shipDate: java.time.LocalDateTime? = null, + val shipDate: java.time.OffsetDateTime? = null, /* Order Status */ val status: Order.Status? = null, val complete: kotlin.Boolean? = null From 23fb51d0a24389e824a641e5328aaa49be88bdd5 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 22 Aug 2018 10:37:11 +0100 Subject: [PATCH 35/39] Fixes after merge with master --- .../codegen/languages/AbstractKotlinCodegen.java | 6 +++--- .../codegen/languages/KotlinSpringServerCodegen.java | 7 +------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index 87f3afc9ecd7..79764ff1b60d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -632,7 +632,7 @@ public String toVarName(String name) { // sanitize name name = sanitizeName(name, "\\W-[\\$]"); - if (name.toLowerCase().matches("^_*class$")) { + if (name.toLowerCase(Locale.ROOT).matches("^_*class$")) { return "propertyClass"; } @@ -646,7 +646,7 @@ public String toVarName(String name) { } if (startsWithTwoUppercaseLetters(name)) { - name = name.substring(0, 2).toLowerCase() + name.substring(2); + name = name.substring(0, 2).toLowerCase(Locale.ROOT) + name.substring(2); } // If name contains special chars -> replace them. @@ -677,7 +677,7 @@ public String toRegularExpression(String pattern) { private boolean startsWithTwoUppercaseLetters(String name) { boolean startsWithTwoUppercaseLetters = false; if (name.length() > 1) { - startsWithTwoUppercaseLetters = name.substring(0, 2).equals(name.substring(0, 2).toUpperCase()); + startsWithTwoUppercaseLetters = name.substring(0, 2).equals(name.substring(0, 2).toUpperCase(Locale.ROOT)); } return startsWithTwoUppercaseLetters; } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 24b80113cd17..10e97b71eacc 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -303,11 +303,6 @@ private void addMustacheLambdas(final Map objs) { @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); - /* TODO the following logic should not need anymore in OAS 3.0 - if ("/".equals(swagger.getBasePath())) { - swagger.setBasePath(""); - } - */ if (!additionalProperties.containsKey(TITLE)) { // The purpose of the title is for: @@ -322,7 +317,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { // Drop any API suffix if (title != null) { title = title.trim().replace(" ", "-"); - if (title.toUpperCase().endsWith("API")) + if (title.toUpperCase(Locale.ROOT).endsWith("API")) title = title.substring(0, title.length() - 3); this.title = camelize(sanitizeName(title), true); From ddec3d2d76d27ea89795feee178424a499e54ee6 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 22 Aug 2018 10:41:45 +0100 Subject: [PATCH 36/39] Revert "Small fix for date time mappings (plus sample re-gen)" This reverts commit 4152dc78b4813da71c675272ca90fb31a333aea1. --- .../languages/AbstractKotlinCodegen.java | 10 ++++++---- .../kotlin/KotlinClientCodegenModelTest.java | 8 ++++---- samples/client/petstore/kotlin/docs/Order.md | 2 +- .../org/openapitools/client/models/Order.kt | 2 +- .../kotlin/org/openapitools/api/Exceptions.kt | 19 +++++++------------ .../kotlin/org/openapitools/model/Order.kt | 2 +- .../kotlin/org/openapitools/api/Exceptions.kt | 19 +++++++------------ .../kotlin/org/openapitools/model/Order.kt | 2 +- 8 files changed, 28 insertions(+), 36 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index 79764ff1b60d..7ec6bc1573ff 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -160,14 +160,16 @@ public AbstractKotlinCodegen() { typeMapping.put("double", "kotlin.Double"); typeMapping.put("ByteArray", "kotlin.ByteArray"); typeMapping.put("number", "java.math.BigDecimal"); - typeMapping.put("date-time", "java.time.OffsetDateTime"); - typeMapping.put("date", "java.time.LocalDate"); + typeMapping.put("date-time", "java.time.LocalDateTime"); + typeMapping.put("date", "java.time.LocalDateTime"); typeMapping.put("file", "java.io.File"); typeMapping.put("array", "kotlin.Array"); typeMapping.put("list", "kotlin.collections.List"); typeMapping.put("map", "kotlin.collections.Map"); typeMapping.put("object", "kotlin.Any"); typeMapping.put("binary", "kotlin.Array"); + typeMapping.put("Date", "java.time.LocalDateTime"); + typeMapping.put("DateTime", "java.time.LocalDateTime"); instantiationTypes.put("array", "kotlin.arrayOf"); instantiationTypes.put("list", "kotlin.arrayOf"); @@ -177,9 +179,9 @@ public AbstractKotlinCodegen() { importMapping.put("BigDecimal", "java.math.BigDecimal"); importMapping.put("UUID", "java.util.UUID"); importMapping.put("File", "java.io.File"); + importMapping.put("Date", "java.util.Date"); importMapping.put("Timestamp", "java.sql.Timestamp"); - importMapping.put("Date", "java.time.LocalDate"); - importMapping.put("DateTime", "java.time.OffsetDateTime"); + importMapping.put("DateTime", "java.time.LocalDateTime"); importMapping.put("LocalDateTime", "java.time.LocalDateTime"); importMapping.put("LocalDate", "java.time.LocalDate"); importMapping.put("LocalTime", "java.time.LocalTime"); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java index 4685eae91949..312a2fa32e3e 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java @@ -105,10 +105,10 @@ public void simpleModelTest() { final CodegenProperty property3 = cm.vars.get(2); Assert.assertEquals(property3.baseName, "createdAt"); - Assert.assertEquals(property3.dataType, "java.time.OffsetDateTime"); + Assert.assertEquals(property3.dataType, "java.time.LocalDateTime"); Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); - Assert.assertEquals(property3.baseType, "java.time.OffsetDateTime"); + Assert.assertEquals(property3.baseType, "java.time.LocalDateTime"); Assert.assertFalse(property3.hasMore); Assert.assertFalse(property3.required); Assert.assertTrue(property3.isNotContainer); @@ -165,10 +165,10 @@ public void selectDateLibraryAsJava8() { final CodegenProperty property3 = cm.vars.get(2); Assert.assertEquals(property3.baseName, "createdAt"); - Assert.assertEquals(property3.dataType, "java.time.OffsetDateTime"); + Assert.assertEquals(property3.dataType, "java.time.LocalDateTime"); Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); - Assert.assertEquals(property3.baseType, "java.time.OffsetDateTime"); + Assert.assertEquals(property3.baseType, "java.time.LocalDateTime"); Assert.assertFalse(property3.hasMore); Assert.assertFalse(property3.required); Assert.assertTrue(property3.isNotContainer); diff --git a/samples/client/petstore/kotlin/docs/Order.md b/samples/client/petstore/kotlin/docs/Order.md index 5112f08958d5..ef31dbf2f4f4 100644 --- a/samples/client/petstore/kotlin/docs/Order.md +++ b/samples/client/petstore/kotlin/docs/Order.md @@ -7,7 +7,7 @@ Name | Type | Description | Notes **id** | **kotlin.Long** | | [optional] **petId** | **kotlin.Long** | | [optional] **quantity** | **kotlin.Int** | | [optional] -**shipDate** | [**java.time.OffsetDateTime**](java.time.OffsetDateTime.md) | | [optional] +**shipDate** | [**java.time.LocalDateTime**](java.time.LocalDateTime.md) | | [optional] **status** | [**inline**](#StatusEnum) | Order Status | [optional] **complete** | **kotlin.Boolean** | | [optional] diff --git a/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt b/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt index 0a163169bef1..44a8b1f896c4 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/org/openapitools/client/models/Order.kt @@ -26,7 +26,7 @@ data class Order ( val id: kotlin.Long? = null, val petId: kotlin.Long? = null, val quantity: kotlin.Int? = null, - val shipDate: java.time.OffsetDateTime? = null, + val shipDate: java.time.LocalDateTime? = null, /* Order Status */ val status: Order.Status? = null, val complete: kotlin.Boolean? = null diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt index 4d8400902aa9..afba2986af28 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -1,12 +1,11 @@ package org.openapitools.api import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import javax.servlet.http.HttpServletResponse -import javax.validation.ConstraintViolationException +import javax.servlet.http.HttpServletRequest -// TODO Extend ApiException for custom exception handling, e.g. the below NotFound exception sealed class ApiException(msg: String, val code: Int) : Exception(msg) class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) @@ -15,15 +14,11 @@ class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : @ControllerAdvice class DefaultExceptionHandler { - @ExceptionHandler(value = [ApiException::class]) - fun onApiException(ex: ApiException, response: HttpServletResponse): Unit = - response.sendError(ex.code, ex.message) + @ExceptionHandler(value = [NotFoundException::class]) + fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.valueOf(ex.code)) @ExceptionHandler(value = [NotImplementedError::class]) - fun onNotImplemented(ex: NotImplementedError, response: HttpServletResponse): Unit = - response.sendError(HttpStatus.NOT_IMPLEMENTED.value()) - - @ExceptionHandler(value = [ConstraintViolationException::class]) - fun onConstraintViolation(ex: ConstraintViolationException, response: HttpServletResponse): Unit = - response.sendError(HttpStatus.BAD_REQUEST.value(), ex.constraintViolations.joinToString(", ") { it.message }) + fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.NOT_IMPLEMENTED) } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index 2a7a639a9cfc..c6036825d371 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -28,7 +28,7 @@ data class Order ( @JsonProperty("quantity") val quantity: kotlin.Int? = null, @ApiModelProperty(value = "") - @JsonProperty("shipDate") val shipDate: java.time.OffsetDateTime? = null, + @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, @ApiModelProperty(value = "Order Status") @JsonProperty("status") val status: Order.Status? = null, diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt index 4d8400902aa9..afba2986af28 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -1,12 +1,11 @@ package org.openapitools.api import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import javax.servlet.http.HttpServletResponse -import javax.validation.ConstraintViolationException +import javax.servlet.http.HttpServletRequest -// TODO Extend ApiException for custom exception handling, e.g. the below NotFound exception sealed class ApiException(msg: String, val code: Int) : Exception(msg) class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) @@ -15,15 +14,11 @@ class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : @ControllerAdvice class DefaultExceptionHandler { - @ExceptionHandler(value = [ApiException::class]) - fun onApiException(ex: ApiException, response: HttpServletResponse): Unit = - response.sendError(ex.code, ex.message) + @ExceptionHandler(value = [NotFoundException::class]) + fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.valueOf(ex.code)) @ExceptionHandler(value = [NotImplementedError::class]) - fun onNotImplemented(ex: NotImplementedError, response: HttpServletResponse): Unit = - response.sendError(HttpStatus.NOT_IMPLEMENTED.value()) - - @ExceptionHandler(value = [ConstraintViolationException::class]) - fun onConstraintViolation(ex: ConstraintViolationException, response: HttpServletResponse): Unit = - response.sendError(HttpStatus.BAD_REQUEST.value(), ex.constraintViolations.joinToString(", ") { it.message }) + fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = + ResponseEntity(HttpStatus.NOT_IMPLEMENTED) } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index 2a7a639a9cfc..c6036825d371 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -28,7 +28,7 @@ data class Order ( @JsonProperty("quantity") val quantity: kotlin.Int? = null, @ApiModelProperty(value = "") - @JsonProperty("shipDate") val shipDate: java.time.OffsetDateTime? = null, + @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, @ApiModelProperty(value = "Order Status") @JsonProperty("status") val status: Order.Status? = null, From 3c47c59154287e73b3602543c249275f0d4c2dc9 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 22 Aug 2018 11:03:34 +0100 Subject: [PATCH 37/39] Moved type mappings to Kotlin Spring generator --- .../codegen/languages/KotlinSpringServerCodegen.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 10e97b71eacc..99fc5a186066 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -183,6 +183,14 @@ public String getHelp() { public void processOpts() { super.processOpts(); + typeMapping.put("date", "java.time.LocalDate"); + typeMapping.put("date-time", "java.time.OffsetDateTime"); + typeMapping.put("Date", "java.time.LocalDate"); + typeMapping.put("DateTime", "java.time.OffsetDateTime"); + + importMapping.put("Date", "java.time.LocalDate"); + importMapping.put("DateTime", "java.time.OffsetDateTime"); + // optional jackson mappings for BigDecimal support importMapping.put("ToStringSerializer", "com.fasterxml.jackson.databind.ser.std.ToStringSerializer"); importMapping.put("JsonSerialize", "com.fasterxml.jackson.databind.annotation.JsonSerialize"); From 521bbbfb35f84dd87aba0c0c1c4def91d4b7cfc1 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 22 Aug 2018 11:06:56 +0100 Subject: [PATCH 38/39] Regenerated samples --- .../kotlin/.openapi-generator/VERSION | 2 +- .../.openapi-generator/VERSION | 2 +- .../kotlin/org/openapitools/api/Exceptions.kt | 19 +++++++++------ .../kotlin/org/openapitools/model/Body.kt | 24 +++++++++++++++++++ .../kotlin/org/openapitools/model/Body1.kt | 24 +++++++++++++++++++ .../kotlin/org/openapitools/model/Order.kt | 2 +- .../ktor/.openapi-generator/VERSION | 2 +- .../petstore/kotlin-server/ktor/README.md | 2 +- .../org/openapitools/server/models/Order.kt | 2 +- .../.openapi-generator/VERSION | 2 +- .../kotlin/org/openapitools/api/Exceptions.kt | 19 +++++++++------ .../kotlin/org/openapitools/model/Order.kt | 2 +- 12 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body.kt create mode 100644 samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body1.kt diff --git a/samples/client/petstore/kotlin/.openapi-generator/VERSION b/samples/client/petstore/kotlin/.openapi-generator/VERSION index c791c986fbb3..be94e6f53db6 100644 --- a/samples/client/petstore/kotlin/.openapi-generator/VERSION +++ b/samples/client/petstore/kotlin/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.3-SNAPSHOT \ No newline at end of file +3.2.2 diff --git a/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION index 105bb87d77b3..acf9bf09db01 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION +++ b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.2-SNAPSHOT \ No newline at end of file +3.2.2 \ No newline at end of file diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt index afba2986af28..4d8400902aa9 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -1,11 +1,12 @@ package org.openapitools.api import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import javax.validation.ConstraintViolationException +// TODO Extend ApiException for custom exception handling, e.g. the below NotFound exception sealed class ApiException(msg: String, val code: Int) : Exception(msg) class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) @@ -14,11 +15,15 @@ class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : @ControllerAdvice class DefaultExceptionHandler { - @ExceptionHandler(value = [NotFoundException::class]) - fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.valueOf(ex.code)) + @ExceptionHandler(value = [ApiException::class]) + fun onApiException(ex: ApiException, response: HttpServletResponse): Unit = + response.sendError(ex.code, ex.message) @ExceptionHandler(value = [NotImplementedError::class]) - fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.NOT_IMPLEMENTED) + fun onNotImplemented(ex: NotImplementedError, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.NOT_IMPLEMENTED.value()) + + @ExceptionHandler(value = [ConstraintViolationException::class]) + fun onConstraintViolation(ex: ConstraintViolationException, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.BAD_REQUEST.value(), ex.constraintViolations.joinToString(", ") { it.message }) } diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body.kt new file mode 100644 index 000000000000..440495ed85ae --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body.kt @@ -0,0 +1,24 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty + +/** + * + * @param name Updated name of the pet + * @param status Updated status of the pet + */ +data class Body ( + + @ApiModelProperty(value = "Updated name of the pet") + @JsonProperty("name") val name: kotlin.String? = null, + + @ApiModelProperty(value = "Updated status of the pet") + @JsonProperty("status") val status: kotlin.String? = null +) { + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body1.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body1.kt new file mode 100644 index 000000000000..0b7b3dc89173 --- /dev/null +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Body1.kt @@ -0,0 +1,24 @@ +package org.openapitools.model + +import java.util.Objects +import com.fasterxml.jackson.annotation.JsonProperty +import javax.validation.Valid +import javax.validation.constraints.* +import io.swagger.annotations.ApiModelProperty + +/** + * + * @param additionalMetadata Additional data to pass to server + * @param file file to upload + */ +data class Body1 ( + + @ApiModelProperty(value = "Additional data to pass to server") + @JsonProperty("additionalMetadata") val additionalMetadata: kotlin.String? = null, + + @ApiModelProperty(value = "file to upload") + @JsonProperty("file") val file: java.io.File? = null +) { + +} + diff --git a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index c6036825d371..2a7a639a9cfc 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/openapi3/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -28,7 +28,7 @@ data class Order ( @JsonProperty("quantity") val quantity: kotlin.Int? = null, @ApiModelProperty(value = "") - @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + @JsonProperty("shipDate") val shipDate: java.time.OffsetDateTime? = null, @ApiModelProperty(value = "Order Status") @JsonProperty("status") val status: Order.Status? = null, diff --git a/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION b/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION index c791c986fbb3..11a4e4a6f776 100644 --- a/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION +++ b/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.3-SNAPSHOT \ No newline at end of file +3.2.3-SNAPSHOT diff --git a/samples/server/petstore/kotlin-server/ktor/README.md b/samples/server/petstore/kotlin-server/ktor/README.md index ab90726d33f1..d7eaa00b4e8e 100644 --- a/samples/server/petstore/kotlin-server/ktor/README.md +++ b/samples/server/petstore/kotlin-server/ktor/README.md @@ -98,7 +98,7 @@ Class | Method | HTTP request | Description - **Type**: OAuth - **Flow**: implicit - **Authorization URL**: http://petstore.swagger.io/api/oauth/dialog -- **Scopes**: +- **Scopes**: - write:pets: modify pets in your account - read:pets: read your pets diff --git a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt index 2eb4fe92bd28..3ec31bfc714f 100644 --- a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt +++ b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/models/Order.kt @@ -25,7 +25,7 @@ data class Order ( val id: kotlin.Long? = null, val petId: kotlin.Long? = null, val quantity: kotlin.Int? = null, - val shipDate: java.time.OffsetDateTime? = null, + val shipDate: java.time.LocalDateTime? = null, /* Order Status */ val status: Order.Status? = null, val complete: kotlin.Boolean? = null diff --git a/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION b/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION index 105bb87d77b3..acf9bf09db01 100644 --- a/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION +++ b/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.2-SNAPSHOT \ No newline at end of file +3.2.2 \ No newline at end of file diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt index afba2986af28..4d8400902aa9 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/api/Exceptions.kt @@ -1,11 +1,12 @@ package org.openapitools.api import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import javax.validation.ConstraintViolationException +// TODO Extend ApiException for custom exception handling, e.g. the below NotFound exception sealed class ApiException(msg: String, val code: Int) : Exception(msg) class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : ApiException(msg, code) @@ -14,11 +15,15 @@ class NotFoundException(msg: String, code: Int = HttpStatus.NOT_FOUND.value()) : @ControllerAdvice class DefaultExceptionHandler { - @ExceptionHandler(value = [NotFoundException::class]) - fun onNotFound(ex: NotFoundException, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.valueOf(ex.code)) + @ExceptionHandler(value = [ApiException::class]) + fun onApiException(ex: ApiException, response: HttpServletResponse): Unit = + response.sendError(ex.code, ex.message) @ExceptionHandler(value = [NotImplementedError::class]) - fun onNotImplemented(ex: NotImplementedError, request: HttpServletRequest): ResponseEntity = - ResponseEntity(HttpStatus.NOT_IMPLEMENTED) + fun onNotImplemented(ex: NotImplementedError, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.NOT_IMPLEMENTED.value()) + + @ExceptionHandler(value = [ConstraintViolationException::class]) + fun onConstraintViolation(ex: ConstraintViolationException, response: HttpServletResponse): Unit = + response.sendError(HttpStatus.BAD_REQUEST.value(), ex.constraintViolations.joinToString(", ") { it.message }) } diff --git a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt index c6036825d371..2a7a639a9cfc 100644 --- a/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt +++ b/samples/server/petstore/kotlin-springboot/src/main/kotlin/org/openapitools/model/Order.kt @@ -28,7 +28,7 @@ data class Order ( @JsonProperty("quantity") val quantity: kotlin.Int? = null, @ApiModelProperty(value = "") - @JsonProperty("shipDate") val shipDate: java.time.LocalDateTime? = null, + @JsonProperty("shipDate") val shipDate: java.time.OffsetDateTime? = null, @ApiModelProperty(value = "Order Status") @JsonProperty("status") val status: Order.Status? = null, From 921edb541e5191b25f69af8aa4c0734faca4d013 Mon Sep 17 00:00:00 2001 From: Adam Drakeford Date: Wed, 22 Aug 2018 17:30:25 +0100 Subject: [PATCH 39/39] Regenerated samples --- samples/client/petstore/kotlin/.openapi-generator/VERSION | 2 +- .../petstore/kotlin-springboot/.openapi-generator/VERSION | 2 +- .../petstore/kotlin-server/ktor/.openapi-generator/VERSION | 2 +- samples/server/petstore/kotlin-server/ktor/README.md | 2 +- .../petstore/kotlin-springboot/.openapi-generator/VERSION | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/client/petstore/kotlin/.openapi-generator/VERSION b/samples/client/petstore/kotlin/.openapi-generator/VERSION index be94e6f53db6..c791c986fbb3 100644 --- a/samples/client/petstore/kotlin/.openapi-generator/VERSION +++ b/samples/client/petstore/kotlin/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.2 +3.2.3-SNAPSHOT \ No newline at end of file diff --git a/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION index acf9bf09db01..c791c986fbb3 100644 --- a/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION +++ b/samples/server/openapi3/petstore/kotlin-springboot/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.2 \ No newline at end of file +3.2.3-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION b/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION index 11a4e4a6f776..c791c986fbb3 100644 --- a/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION +++ b/samples/server/petstore/kotlin-server/ktor/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.3-SNAPSHOT +3.2.3-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/kotlin-server/ktor/README.md b/samples/server/petstore/kotlin-server/ktor/README.md index d7eaa00b4e8e..ab90726d33f1 100644 --- a/samples/server/petstore/kotlin-server/ktor/README.md +++ b/samples/server/petstore/kotlin-server/ktor/README.md @@ -98,7 +98,7 @@ Class | Method | HTTP request | Description - **Type**: OAuth - **Flow**: implicit - **Authorization URL**: http://petstore.swagger.io/api/oauth/dialog -- **Scopes**: +- **Scopes**: - write:pets: modify pets in your account - read:pets: read your pets diff --git a/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION b/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION index acf9bf09db01..c791c986fbb3 100644 --- a/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION +++ b/samples/server/petstore/kotlin-springboot/.openapi-generator/VERSION @@ -1 +1 @@ -3.2.2 \ No newline at end of file +3.2.3-SNAPSHOT \ No newline at end of file