[KOTLIN] Spring Boot Server Generator (#820)

* Kotlin Spring initial bootstrap

* Basic configuration construction for Kotlin Spring

* Wired up with comand line client

* Initial kotlin spring boot application generated using gradle kotlin-dsl

* Added basic support for generating models

* Basic controllers generated without endpoints generated

* Basic spring boot app generated with models and controllers

* Added fix for type mapping in AbstractKotlinCodegen. Originally it was mapping list o kotlin.Array instead of kotlin.collections.List

* Fixed return type mapping

* Sorted bash springboot petstore generator script

* Implemented toVarName in AbstractKotlinCodegen to better handle some edgecases

* Checking for reserved words or numerical starting class names in AbstractKotlinCodegen

* Implemented toOperationId in AbstractKotlinCodegen

* Fixed types that were not correctly being mapped to primitives (byte / arrayOf / mapOf)

* Escaping dollar symbols in function names

* Added support for outter enum classes

* Added basic support for generating services

* Removed option for generated config package. Added option to enable/disable generated global exception handler

* Added configuration option to generate gradle. Generated maven pom.xml file as default

* Fixed up bash scripts for generating test sample code

* Added configurable option for Swagger Annotations

* Added configurable option for generating service interfaces and service implementations

* Added README generation

* Enable optional bean validation

* Added kotlin spring sample to CircleCI pom.xml

* Removed kotlin spring boot from .gitignore

* 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

* 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

* Updated samples

* Generating ConstraintViolation Exception Handler, as Springboot doesnt correctly catch the error and return bad request. Handling other exceptions a litle better

* Small fix for date time mappings (plus sample re-gen)

* Minor fix in README template, where port was using wrong variable

* Fix missing jackson-dataformat-xml dependency

* Fix build - needed to re-run kotlin-server-petstore.sh

* Fixes after merge with master

* Revert "Small fix for date time mappings (plus sample re-gen)"

This reverts commit 4152dc78b4813da71c675272ca90fb31a333aea1.

* Moved type mappings to Kotlin Spring generator

* Regenerated samples

* Regenerated samples
This commit is contained in:
Adam Drakeford
2018-08-27 16:54:53 +01:00
committed by William Cheng
parent 5cd5143b80
commit 8689227b3e
87 changed files with 3368 additions and 13 deletions

4
.gitignore vendored
View File

@@ -115,14 +115,14 @@ samples/client/petstore/swift/**/SwaggerClientTests/SwaggerClient.xcworkspace/xc
samples/client/petstore/swift/**/SwaggerClientTests/Pods/ samples/client/petstore/swift/**/SwaggerClientTests/Pods/
#samples/client/petstore/swift/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcuserdata #samples/client/petstore/swift/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcuserdata
#samples/client/petstore/swift/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcshareddata/xcschemes #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 # Swift3
samples/client/petstore/swift3/**/SwaggerClientTests/SwaggerClient.xcodeproj/xcuserdata samples/client/petstore/swift3/**/SwaggerClientTests/SwaggerClient.xcodeproj/xcuserdata
samples/client/petstore/swift3/**/SwaggerClientTests/SwaggerClient.xcworkspace/xcuserdata samples/client/petstore/swift3/**/SwaggerClientTests/SwaggerClient.xcworkspace/xcuserdata
#samples/client/petstore/swift3/**/SwaggerClientTests/Pods/ #samples/client/petstore/swift3/**/SwaggerClientTests/Pods/
#samples/client/petstore/swift3/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcuserdata #samples/client/petstore/swift3/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcuserdata
#samples/client/petstore/swift3/**/SwaggerClientTests/Pods/Pods.xcodeproj/xcshareddata/xcschemes #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# # C#
*.csproj.user *.csproj.user

View File

@@ -957,6 +957,7 @@
<module>samples/server/petstore/scala-lagom-server</module> <module>samples/server/petstore/scala-lagom-server</module>
<module>samples/server/petstore/scalatra</module> <module>samples/server/petstore/scalatra</module>
<module>samples/server/petstore/finch</module> <module>samples/server/petstore/finch</module>
<module>samples/server/petstore/kotlin-springboot</module>
</modules> </modules>
</profile> </profile>
</profiles> </profiles>

View File

@@ -0,0 +1,35 @@
#!/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
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,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
echo "Generating Kotling Spring Boot server..."
java $JAVA_OPTS -jar $executable $ags

View File

@@ -0,0 +1,35 @@
#!/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
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,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
echo "Generating Kotling Spring Boot server..."
java $JAVA_OPTS -jar $executable $ags

View File

@@ -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\2_0\petstore.yaml -g kotlin-spring -o samples\server\petstore\kotlin-springboot --additional-properties=library=spring-boot
java %JAVA_OPTS% -jar %executable% %ags%

View File

@@ -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%

View File

@@ -19,6 +19,7 @@ package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption; import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConfig; import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenConstants;
@@ -28,11 +29,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
public abstract class AbstractKotlinCodegen extends DefaultCodegen implements CodegenConfig { public abstract class AbstractKotlinCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractKotlinCodegen.class); private static final Logger LOGGER = LoggerFactory.getLogger(AbstractKotlinCodegen.class);
@@ -55,6 +52,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
languageSpecificPrimitives = new HashSet<String>(Arrays.asList( languageSpecificPrimitives = new HashSet<String>(Arrays.asList(
"kotlin.Byte", "kotlin.Byte",
"kotlin.ByteArray",
"kotlin.Short", "kotlin.Short",
"kotlin.Int", "kotlin.Int",
"kotlin.Long", "kotlin.Long",
@@ -139,6 +137,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
defaultIncludes = new HashSet<String>(Arrays.asList( defaultIncludes = new HashSet<String>(Arrays.asList(
"kotlin.Byte", "kotlin.Byte",
"kotlin.ByteArray",
"kotlin.Short", "kotlin.Short",
"kotlin.Int", "kotlin.Int",
"kotlin.Long", "kotlin.Long",
@@ -159,21 +158,22 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
typeMapping.put("float", "kotlin.Float"); typeMapping.put("float", "kotlin.Float");
typeMapping.put("long", "kotlin.Long"); typeMapping.put("long", "kotlin.Long");
typeMapping.put("double", "kotlin.Double"); typeMapping.put("double", "kotlin.Double");
typeMapping.put("ByteArray", "kotlin.ByteArray");
typeMapping.put("number", "java.math.BigDecimal"); typeMapping.put("number", "java.math.BigDecimal");
typeMapping.put("date-time", "java.time.LocalDateTime"); typeMapping.put("date-time", "java.time.LocalDateTime");
typeMapping.put("date", "java.time.LocalDateTime"); typeMapping.put("date", "java.time.LocalDateTime");
typeMapping.put("file", "java.io.File"); typeMapping.put("file", "java.io.File");
typeMapping.put("array", "kotlin.Array"); typeMapping.put("array", "kotlin.Array");
typeMapping.put("list", "kotlin.Array"); typeMapping.put("list", "kotlin.collections.List");
typeMapping.put("map", "kotlin.collections.Map"); typeMapping.put("map", "kotlin.collections.Map");
typeMapping.put("object", "kotlin.Any"); typeMapping.put("object", "kotlin.Any");
typeMapping.put("binary", "kotlin.Array<kotlin.Byte>"); typeMapping.put("binary", "kotlin.Array<kotlin.Byte>");
typeMapping.put("Date", "java.time.LocalDateTime"); typeMapping.put("Date", "java.time.LocalDateTime");
typeMapping.put("DateTime", "java.time.LocalDateTime"); typeMapping.put("DateTime", "java.time.LocalDateTime");
instantiationTypes.put("array", "arrayOf"); instantiationTypes.put("array", "kotlin.arrayOf");
instantiationTypes.put("list", "arrayOf"); instantiationTypes.put("list", "kotlin.arrayOf");
instantiationTypes.put("map", "mapOf"); instantiationTypes.put("map", "kotlin.mapOf");
importMapping = new HashMap<String, String>(); importMapping = new HashMap<String, String>();
importMapping.put("BigDecimal", "java.math.BigDecimal"); importMapping.put("BigDecimal", "java.math.BigDecimal");
@@ -473,13 +473,53 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
// Camelize name of nested properties // Camelize name of nested properties
modifiedName = camelize(modifiedName); modifiedName = camelize(modifiedName);
if (reservedWords.contains(modifiedName)) { // model name cannot use reserved keyword, e.g. return
modifiedName = escapeReservedWord(modifiedName); 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); 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 @Override
public String toModelFilename(String name) { public String toModelFilename(String name) {
// Should be the same as the model name // Should be the same as the model name
@@ -577,4 +617,70 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
public boolean isDataTypeString(final String dataType) { public boolean isDataTypeString(final String dataType) {
return "String".equals(dataType) || "kotlin.String".equals(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
name = sanitizeName(name, "\\W-[\\$]");
if (name.toLowerCase(Locale.ROOT).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(Locale.ROOT) + name.substring(2);
}
// If name contains special chars -> replace them.
if ((name.chars().anyMatch(character -> specialCharReplacements.keySet().contains("" + ((char) character))))) {
List<String> 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 or containing dollar symbol, escape it
if (isReservedWord(name) || name.matches("(^\\d.*)|(.*[$].*)")) {
name = escapeReservedWord(name);
}
return name;
}
@Override
public String toRegularExpression(String pattern) {
return escapeText(pattern);
}
private boolean startsWithTwoUppercaseLetters(String name) {
boolean startsWithTwoUppercaseLetters = false;
if (name.length() > 1) {
startsWithTwoUppercaseLetters = name.substring(0, 2).equals(name.substring(0, 2).toUpperCase(Locale.ROOT));
}
return startsWithTwoUppercaseLetters;
}
} }

View File

@@ -0,0 +1,485 @@
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;
import org.openapitools.codegen.utils.URLPathUtils;
import org.slf4j.Logger;
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;
public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
implements BeanValidationFeatures {
private static Logger LOGGER =
LoggerFactory.getLogger(KotlinSpringServerCodegen.class);
private static final HashSet<String> VARIABLE_RESERVED_WORDS =
new HashSet<String>(Arrays.asList(
"ApiClient",
"ApiException",
"ApiResponse"
));
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";
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";
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;
private boolean serviceInterface = false;
private boolean serviceImplementation = false;
public KotlinSpringServerCodegen() {
super();
reservedWords.addAll(VARIABLE_RESERVED_WORDS);
outputFolder = "generated-code/kotlin-spring";
apiTestTemplateFiles.clear(); // TODO: add test template
embeddedTemplateDir = templateDir = "kotlin-spring";
artifactId = "openapi-spring";
basePackage = "org.openapitools";
apiPackage = "org.openapitools.api";
modelPackage = "org.openapitools.model";
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);
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);
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);
addSwitch(USE_BEANVALIDATION, "Use BeanValidation API annotations to validate data types", useBeanValidation);
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
setLibrary(SPRING_BOOT);
CliOption cliOpt = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use");
cliOpt.setDefault(SPRING_BOOT);
cliOpt.setEnum(supportedLibraries);
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;
}
public boolean getGradleBuildFile() {
return this.gradleBuildFile;
}
public void setGradleBuildFile(boolean gradleBuildFile) {
this.gradleBuildFile = gradleBuildFile;
}
public boolean getSwaggerAnnotations() {
return this.swaggerAnnotations;
}
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;
}
public boolean getUseBeanValidation() {
return this.useBeanValidation;
}
@Override
public void setUseBeanValidation(boolean useBeanValidation) {
this.useBeanValidation = useBeanValidation;
}
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}
@Override
public String getName() {
return "kotlin-spring";
}
@Override
public String getHelp() {
return "Generates a Kotlin Spring application.";
}
@Override
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");
// 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("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);
}
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(EXCEPTION_HANDLER)) {
this.setExceptionHandler(Boolean.valueOf(additionalProperties.get(EXCEPTION_HANDLER).toString()));
}
writePropertyBack(EXCEPTION_HANDLER, exceptionHandler);
if (additionalProperties.containsKey(GRADLE_BUILD_FILE)) {
this.setGradleBuildFile(Boolean.valueOf(additionalProperties.get(GRADLE_BUILD_FILE).toString()));
}
writePropertyBack(GRADLE_BUILD_FILE, gradleBuildFile);
if (additionalProperties.containsKey(SWAGGER_ANNOTATIONS)) {
this.setSwaggerAnnotations(Boolean.valueOf(additionalProperties.get(SWAGGER_ANNOTATIONS).toString()));
}
writePropertyBack(SWAGGER_ANNOTATIONS, swaggerAnnotations);
if (additionalProperties.containsKey(SERVICE_INTERFACE)) {
this.setServiceInterface(Boolean.valueOf(additionalProperties.get(SERVICE_INTERFACE).toString()));
}
writePropertyBack(SERVICE_INTERFACE, serviceInterface);
if (additionalProperties.containsKey(SERVICE_IMPLEMENTATION)) {
this.setServiceImplementation(Boolean.valueOf(additionalProperties.get(SERVICE_IMPLEMENTATION).toString()));
}
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");
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
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");
}
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");
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"));
}
addMustacheLambdas(additionalProperties);
// spring uses the jackson lib, and we disallow configuration.
additionalProperties.put("jackson", "true");
}
private void addMustacheLambdas(final Map<String, Object> objs) {
Map<String, Mustache.Lambda> lambdas =
new ImmutableMap.Builder<String, Mustache.Lambda>()
.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);
if (!additionalProperties.containsKey(TITLE)) {
// 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
if (title != null) {
title = title.trim().replace(" ", "-");
if (title.toUpperCase(Locale.ROOT).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));
}
// TODO: Handle tags
}
@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 {
//Needed imports for Jackson's JsonCreator
if (additionalProperties.containsKey("jackson")) {
model.imports.add("JsonCreator");
}
}
}
@Override
public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
objs = super.postProcessModelsEnum(objs);
//Add imports for Jackson
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
List<Object> models = (List<Object>) objs.get("models");
models.stream()
.map(mo -> (Map<String, Object>) 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<String, String> item = new HashMap<>();
item.put("import", importMapping.get("JsonValue"));
imports.add(item);
});
return objs;
}
@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
if (operations != null) {
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
ops.forEach(operation -> {
List<CodegenResponse> 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(final String returnType, DataTypeAssigner dataTypeAssigner) {
if (returnType == null) {
dataTypeAssigner.setReturnType("Unit");
} else if (returnType.startsWith("kotlin.Array")) {
int end = returnType.lastIndexOf(">");
if (end > 0) {
dataTypeAssigner.setReturnType(returnType.substring("kotlin.Array<".length(), end).trim());
dataTypeAssigner.setReturnContainer("List");
}
} else if (returnType.startsWith("kotlin.collections.Map")) {
int end = returnType.lastIndexOf(">");
if (end > 0) {
dataTypeAssigner.setReturnType(returnType.substring("kotlin.collections.Map<".length(), end).split(",")[1].trim());
dataTypeAssigner.setReturnContainer("Map");
}
}
}
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));
}
}
}

View File

@@ -91,3 +91,4 @@ org.openapitools.codegen.languages.TypeScriptFetchClientCodegen
org.openapitools.codegen.languages.TypeScriptInversifyClientCodegen org.openapitools.codegen.languages.TypeScriptInversifyClientCodegen
org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen
org.openapitools.codegen.languages.TypeScriptNodeClientCodegen org.openapitools.codegen.languages.TypeScriptNodeClientCodegen
org.openapitools.codegen.languages.KotlinSpringServerCodegen

View File

@@ -0,0 +1,70 @@
package {{package}}
{{#imports}}import {{import}}
{{/imports}}
{{#swaggerAnnotations}}
import io.swagger.annotations.*
{{/swaggerAnnotations}}
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
{{#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}}
{{=<% %>=}}
@RequestMapping("\${openapi.<%title%>.base-path:<%contextPath%>}")
<%={{ }}=%>
{{#operations}}
class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) val service: {{classname}}Service{{/serviceInterface}}) {
{{#operation}}
{{#swaggerAnnotations}}
@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}}]){{/swaggerAnnotations}}
@RequestMapping(
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}}
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 {{>returnValue}}
}
{{/operation}}
}
{{/operations}}

View File

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

View File

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

View File

@@ -0,0 +1 @@
{{! PathParam is always required, no @NotNull necessary }}{{>beanValidationPath}}

View File

@@ -0,0 +1 @@
{{#required}}@NotNull {{/required}}{{>beanValidationPath}}

View File

@@ -0,0 +1 @@
{{#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}}

View File

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

View File

@@ -0,0 +1,4 @@
{{#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}}

View File

@@ -0,0 +1,4 @@
{{#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}}

View File

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

View File

@@ -0,0 +1,29 @@
package {{apiPackage}}
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
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)
@ControllerAdvice
class DefaultExceptionHandler {
@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, 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 })
}

View File

@@ -0,0 +1 @@
{{#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}}

View File

@@ -0,0 +1 @@
{{#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}}

View File

@@ -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/{{artifactId}}-{{artifactVersion}}.jar
```
To build the project using gradle, run:
```bash
gradle build && java -jar build/libs/{{artifactId}}-{{artifactVersion}}.jar
```
If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:{{serverPort}}/)

View File

@@ -0,0 +1,3 @@
spring.application.name={{title}}
server.port={{serverPort}}
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false

View File

@@ -0,0 +1,47 @@
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<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
plugins {
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
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")
{{#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")
}
}

View File

@@ -0,0 +1,109 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>{{groupId}}</groupId>
<artifactId>{{artifactId}}</artifactId>
<packaging>jar</packaging>
<name>{{artifactId}}</name>
<version>{{artifactVersion}}</version>
<properties>
<kotlin.version>1.2.60</kotlin.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
{{#swaggerAnnotations}}
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
{{/swaggerAnnotations}}
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
{{#useBeanValidation}}
<!-- Bean Validation API support -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
{{/useBeanValidation}}
</dependencies>
</project>

View File

@@ -0,0 +1 @@
rootProject.name = "{{artifactId}}"

View File

@@ -0,0 +1,14 @@
package {{basePackage}}
import org.springframework.boot.runApplication
import org.springframework.context.annotation.ComponentScan
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
@ComponentScan(basePackages = ["{{basePackage}}", "{{apiPackage}}", "{{modelPackage}}"])
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}

View File

@@ -0,0 +1,18 @@
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}}
{{#isEnum}}{{>enumClass}}{{/isEnum}}{{^isEnum}}{{>dataClass}}{{/isEnum}}
{{/model}}
{{/models}}

View File

@@ -0,0 +1 @@
{{#useOptional}}{{#required}}{{{dataType}}}{{/required}}{{^required}}Optional<{{{dataType}}}>{{/required}}{{/useOptional}}{{^useOptional}}{{{dataType}}}{{/useOptional}}

View File

@@ -0,0 +1 @@
{{#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}}

View File

@@ -0,0 +1 @@
{{#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}}

View File

@@ -0,0 +1 @@
{{#isMapContainer}}{{#reactive}}Mono<{{/reactive}}Map<String, {{{returnType}}}{{#reactive}}>{{/reactive}}>{{/isMapContainer}}{{#isListContainer}}{{#reactive}}Flux{{/reactive}}{{^reactive}}List{{/reactive}}<{{{returnType}}}>{{/isListContainer}}{{^returnContainer}}{{#reactive}}Mono<{{{returnType}}}>{{/reactive}}{{^reactive}}{{{returnType}}}{{/reactive}}{{/returnContainer}}

View File

@@ -0,0 +1 @@
{{#serviceInterface}}ResponseEntity(service.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}), HttpStatus.OK){{/serviceInterface}}{{^serviceInterface}}ResponseEntity(HttpStatus.NOT_IMPLEMENTED){{/serviceInterface}}

View File

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

View File

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

View File

@@ -0,0 +1,115 @@
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();
final 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.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.getServerPort(), "8080");
Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.SERVER_PORT), "8080");
}
@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.setServerPort("8181");
codegen.setExceptionHandler(false);
codegen.setGradleBuildFile(false);
codegen.setSwaggerAnnotations(true);
codegen.setServiceInterface(true);
codegen.setServiceImplementation(true);
codegen.setUseBeanValidation(false);
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.getServerPort(), "8181");
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);
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);
Assert.assertFalse(codegen.getUseBeanValidation());
Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.USE_BEANVALIDATION), false);
}
@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.SERVER_PORT, "8088");
codegen.additionalProperties().put(KotlinSpringServerCodegen.EXCEPTION_HANDLER, false);
codegen.additionalProperties().put(KotlinSpringServerCodegen.GRADLE_BUILD_FILE, false);
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();
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.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);
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);
Assert.assertFalse(codegen.getUseBeanValidation());
Assert.assertEquals(codegen.additionalProperties().get(KotlinSpringServerCodegen.USE_BEANVALIDATION), false);
}
}

View File

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

View File

@@ -0,0 +1 @@
3.2.3-SNAPSHOT

View File

@@ -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:8080/)

View File

@@ -0,0 +1,45 @@
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<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
plugins {
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
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.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")
}
}

View File

@@ -0,0 +1,105 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.openapitools</groupId>
<artifactId>openapi-spring</artifactId>
<packaging>jar</packaging>
<name>openapi-spring</name>
<version>1.0.0</version>
<properties>
<kotlin.version>1.2.60</kotlin.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- Bean Validation API support -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1 @@
rootProject.name = "openapi-spring"

View File

@@ -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<String>) {
runApplication<Application>(*args)
}

View File

@@ -0,0 +1,29 @@
package org.openapitools.api
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
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)
@ControllerAdvice
class DefaultExceptionHandler {
@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, 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 })
}

View File

@@ -0,0 +1,159 @@
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.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) {
@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 ) @Valid @RequestBody pet: Pet): ResponseEntity<Unit> {
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<Unit> {
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(@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<kotlin.String>): ResponseEntity<List<Pet>> {
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(@NotNull @ApiParam(value = "Tags to filter by", required = true) @Valid @RequestParam(value = "tags", required = true) tags: kotlin.Array<kotlin.String>): ResponseEntity<List<Pet>> {
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<Pet> {
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 ) @Valid @RequestBody pet: Pet): ResponseEntity<Unit> {
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<Unit> {
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") @Valid @RequestPart("file") file: MultipartFile): ResponseEntity<ModelApiResponse> {
return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK)
}
}

View File

@@ -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<kotlin.String>): List<Pet>
fun findPetsByTags(tags: kotlin.Array<kotlin.String>): List<Pet>
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
}

View File

@@ -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<kotlin.String>): List<Pet> {
TODO("Implement me")
}
override fun findPetsByTags(tags: kotlin.Array<kotlin.String>): List<Pet> {
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")
}
}

View File

@@ -0,0 +1,93 @@
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.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) {
@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<Unit> {
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<Map<String, kotlin.Int>> {
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(@Min(1L) @Max(5L) @ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity<Order> {
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 ) @Valid @RequestBody order: Order): ResponseEntity<Order> {
return ResponseEntity(service.placeOrder(order), HttpStatus.OK)
}
}

View File

@@ -0,0 +1,14 @@
package org.openapitools.api
import org.openapitools.model.Order
interface StoreApiService {
fun deleteOrder(orderId: kotlin.String): Unit
fun getInventory(): Map<String, kotlin.Int>
fun getOrderById(orderId: kotlin.Long): Order
fun placeOrder(order: Order): Order
}

View File

@@ -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<String, kotlin.Int> {
TODO("Implement me")
}
override fun getOrderById(orderId: kotlin.Long): Order {
TODO("Implement me")
}
override fun placeOrder(order: Order): Order {
TODO("Implement me")
}
}

View File

@@ -0,0 +1,144 @@
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.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) {
@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 ) @Valid @RequestBody user: User): ResponseEntity<Unit> {
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 ) @Valid @RequestBody user: kotlin.Array<User>): ResponseEntity<Unit> {
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 ) @Valid @RequestBody user: kotlin.Array<User>): ResponseEntity<Unit> {
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<Unit> {
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<User> {
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(@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<kotlin.String> {
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<Unit> {
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 ) @Valid @RequestBody user: User): ResponseEntity<Unit> {
return ResponseEntity(service.updateUser(username, user), HttpStatus.OK)
}
}

View File

@@ -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<User>): Unit
fun createUsersWithListInput(user: kotlin.Array<User>): 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
}

View File

@@ -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<User>): Unit {
TODO("Implement me")
}
override fun createUsersWithListInput(user: kotlin.Array<User>): 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")
}
}

View File

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

View File

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

View File

@@ -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
/**
* A category for a pet
* @param id
* @param name
*/
data class Category (
@ApiModelProperty(value = "")
@JsonProperty("id") val id: kotlin.Long? = null,
@ApiModelProperty(value = "")
@JsonProperty("name") val name: kotlin.String? = null
) {
}

View File

@@ -0,0 +1,28 @@
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
/**
* Describes the result of uploading an image resource
* @param code
* @param type
* @param message
*/
data class ModelApiResponse (
@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
) {
}

View File

@@ -0,0 +1,55 @@
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.*
import io.swagger.annotations.ApiModelProperty
/**
* 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 (
@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.OffsetDateTime? = null,
@ApiModelProperty(value = "Order Status")
@JsonProperty("status") val status: Order.Status? = null,
@ApiModelProperty(value = "")
@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");
}
}

View File

@@ -0,0 +1,59 @@
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.*
import io.swagger.annotations.ApiModelProperty
/**
* 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 (
@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<kotlin.String>,
@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<Tag>? = null,
@ApiModelProperty(value = "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");
}
}

View File

@@ -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
/**
* A tag for a pet
* @param id
* @param name
*/
data class Tag (
@ApiModelProperty(value = "")
@JsonProperty("id") val id: kotlin.Long? = null,
@ApiModelProperty(value = "")
@JsonProperty("name") val name: kotlin.String? = null
) {
}

View File

@@ -0,0 +1,48 @@
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
/**
* 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 (
@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
) {
}

View File

@@ -0,0 +1,3 @@
spring.application.name=openAPIPetstore
server.port=8080
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false

View File

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

View File

@@ -0,0 +1 @@
3.2.3-SNAPSHOT

View File

@@ -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:8080/)

View File

@@ -0,0 +1,45 @@
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<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
plugins {
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
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.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")
}
}

View File

@@ -0,0 +1,105 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.openapitools</groupId>
<artifactId>openapi-spring</artifactId>
<packaging>jar</packaging>
<name>openapi-spring</name>
<version>1.0.0</version>
<properties>
<kotlin.version>1.2.60</kotlin.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- Bean Validation API support -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1 @@
rootProject.name = "openapi-spring"

View File

@@ -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<String>) {
runApplication<Application>(*args)
}

View File

@@ -0,0 +1,29 @@
package org.openapitools.api
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
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)
@ControllerAdvice
class DefaultExceptionHandler {
@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, 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 })
}

View File

@@ -0,0 +1,159 @@
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.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) {
@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 ) @Valid @RequestBody pet: Pet): ResponseEntity<Unit> {
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<Unit> {
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(@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<kotlin.String>): ResponseEntity<List<Pet>> {
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(@NotNull @ApiParam(value = "Tags to filter by", required = true) @Valid @RequestParam(value = "tags", required = true) tags: kotlin.Array<kotlin.String>): ResponseEntity<List<Pet>> {
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<Pet> {
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 ) @Valid @RequestBody pet: Pet): ResponseEntity<Unit> {
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<Unit> {
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") @Valid @RequestPart("file") file: MultipartFile): ResponseEntity<ModelApiResponse> {
return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK)
}
}

View File

@@ -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<kotlin.String>): List<Pet>
fun findPetsByTags(tags: kotlin.Array<kotlin.String>): List<Pet>
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
}

View File

@@ -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<kotlin.String>): List<Pet> {
TODO("Implement me")
}
override fun findPetsByTags(tags: kotlin.Array<kotlin.String>): List<Pet> {
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")
}
}

View File

@@ -0,0 +1,92 @@
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.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) {
@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<Unit> {
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<Map<String, kotlin.Int>> {
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(@Min(1L) @Max(5L) @ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: kotlin.Long): ResponseEntity<Order> {
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 ) @Valid @RequestBody order: Order): ResponseEntity<Order> {
return ResponseEntity(service.placeOrder(order), HttpStatus.OK)
}
}

View File

@@ -0,0 +1,14 @@
package org.openapitools.api
import org.openapitools.model.Order
interface StoreApiService {
fun deleteOrder(orderId: kotlin.String): Unit
fun getInventory(): Map<String, kotlin.Int>
fun getOrderById(orderId: kotlin.Long): Order
fun placeOrder(order: Order): Order
}

View File

@@ -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<String, kotlin.Int> {
TODO("Implement me")
}
override fun getOrderById(orderId: kotlin.Long): Order {
TODO("Implement me")
}
override fun placeOrder(order: Order): Order {
TODO("Implement me")
}
}

View File

@@ -0,0 +1,140 @@
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.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) {
@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 ) @Valid @RequestBody user: User): ResponseEntity<Unit> {
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 ) @Valid @RequestBody user: kotlin.Array<User>): ResponseEntity<Unit> {
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 ) @Valid @RequestBody user: kotlin.Array<User>): ResponseEntity<Unit> {
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<Unit> {
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<User> {
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(@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<kotlin.String> {
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<Unit> {
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 ) @Valid @RequestBody user: User): ResponseEntity<Unit> {
return ResponseEntity(service.updateUser(username, user), HttpStatus.OK)
}
}

View File

@@ -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<User>): Unit
fun createUsersWithListInput(user: kotlin.Array<User>): 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
}

View File

@@ -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<User>): Unit {
TODO("Implement me")
}
override fun createUsersWithListInput(user: kotlin.Array<User>): 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")
}
}

View File

@@ -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
/**
* A category for a pet
* @param id
* @param name
*/
data class Category (
@ApiModelProperty(value = "")
@JsonProperty("id") val id: kotlin.Long? = null,
@ApiModelProperty(value = "")
@JsonProperty("name") val name: kotlin.String? = null
) {
}

View File

@@ -0,0 +1,28 @@
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
/**
* Describes the result of uploading an image resource
* @param code
* @param type
* @param message
*/
data class ModelApiResponse (
@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
) {
}

View File

@@ -0,0 +1,55 @@
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.*
import io.swagger.annotations.ApiModelProperty
/**
* 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 (
@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.OffsetDateTime? = null,
@ApiModelProperty(value = "Order Status")
@JsonProperty("status") val status: Order.Status? = null,
@ApiModelProperty(value = "")
@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");
}
}

View File

@@ -0,0 +1,59 @@
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.*
import io.swagger.annotations.ApiModelProperty
/**
* 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 (
@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<kotlin.String>,
@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<Tag>? = null,
@ApiModelProperty(value = "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");
}
}

View File

@@ -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
/**
* A tag for a pet
* @param id
* @param name
*/
data class Tag (
@ApiModelProperty(value = "")
@JsonProperty("id") val id: kotlin.Long? = null,
@ApiModelProperty(value = "")
@JsonProperty("name") val name: kotlin.String? = null
) {
}

View File

@@ -0,0 +1,48 @@
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
/**
* 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 (
@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
) {
}

View File

@@ -0,0 +1,3 @@
spring.application.name=openAPIPetstore
server.port=8080
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false