diff --git a/.github/workflows/samples-kotlin-client.yaml b/.github/workflows/samples-kotlin-client.yaml
index 653119c4130..d0ead8cbc20 100644
--- a/.github/workflows/samples-kotlin-client.yaml
+++ b/.github/workflows/samples-kotlin-client.yaml
@@ -56,6 +56,7 @@ jobs:
- samples/client/petstore/kotlin-jvm-vertx-jackson
- samples/client/petstore/kotlin-jvm-vertx-jackson-coroutines
- samples/client/petstore/kotlin-jvm-vertx-moshi
+ - samples/client/petstore/kotlin-spring-cloud
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
diff --git a/bin/configs/kotlin-spring-cloud.yaml b/bin/configs/kotlin-spring-cloud.yaml
new file mode 100644
index 00000000000..10e6f95a805
--- /dev/null
+++ b/bin/configs/kotlin-spring-cloud.yaml
@@ -0,0 +1,12 @@
+generatorName: kotlin-spring
+outputDir: samples/client/petstore/kotlin-spring-cloud
+library: spring-cloud
+inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
+templateDir: modules/openapi-generator/src/main/resources/kotlin-spring
+additionalProperties:
+ documentationProvider: none
+ annotationLibrary: none
+ useSwaggerUI: "false"
+ serializableModel: "true"
+ beanValidations: "true"
+ interfaceOnly: "true"
diff --git a/docs/generators/kotlin-spring.md b/docs/generators/kotlin-spring.md
index 0bf820d705d..24c83a9bf70 100644
--- a/docs/generators/kotlin-spring.md
+++ b/docs/generators/kotlin-spring.md
@@ -26,6 +26,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|artifactVersion|Generated artifact's package version.| |1.0.0|
|basePackage|base package (invokerPackage) for generated code| |org.openapitools|
|beanQualifiers|Whether to add fully-qualifier class names as bean qualifiers in @Component and @RestController annotations. May be used to prevent bean names clash if multiple generated libraries (contexts) added to single project.| |false|
+|configPackage|configuration package for generated code| |org.openapitools.configuration|
|delegatePattern|Whether to generate the server files using the delegate pattern| |false|
|documentationProvider|Select the OpenAPI documentation provider.|
- **none**
- Do not publish an OpenAPI specification.
- **source**
- Publish the original input OpenAPI specification.
- **springfox**
- Generate an OpenAPI 2 (fka Swagger RESTful API Documentation Specification) specification using SpringFox 2.x. Deprecated (for removal); use springdoc instead.
- **springdoc**
- Generate an OpenAPI 3 specification using SpringDoc.
|springdoc|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
@@ -33,7 +34,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|gradleBuildFile|generate a gradle build file using the Kotlin DSL| |true|
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|interfaceOnly|Whether to generate only API interface stubs without the server files.| |false|
-|library|library template (sub-template)|- **spring-boot**
- Spring-boot Server application.
|spring-boot|
+|library|library template (sub-template)|- **spring-boot**
- Spring-boot Server application.
- **spring-cloud**
- Spring-Cloud-Feign client with Spring-Boot auto-configured settings.
|spring-boot|
|modelMutable|Create mutable models| |false|
|modelPackage|model package for generated code| |org.openapitools.model|
|packageName|Generated artifact package name.| |org.openapitools|
@@ -50,6 +51,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|sourceFolder|source folder for generated code| |src/main/kotlin|
|title|server title name or client service name| |OpenAPI Kotlin Spring|
|useBeanValidation|Use BeanValidation API annotations to validate data types| |true|
+|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|
|useTags|Whether to use tags for creating interface and controller class names| |false|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
index 2be4589572a..540cef17237 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
@@ -22,11 +22,24 @@ import com.samskivert.mustache.Mustache.Lambda;
import com.samskivert.mustache.Template;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
-import org.openapitools.codegen.*;
+import org.openapitools.codegen.CliOption;
+import org.openapitools.codegen.CodegenConstants;
+import org.openapitools.codegen.CodegenModel;
+import org.openapitools.codegen.CodegenOperation;
+import org.openapitools.codegen.CodegenParameter;
+import org.openapitools.codegen.CodegenProperty;
+import org.openapitools.codegen.CodegenResponse;
+import org.openapitools.codegen.CodegenType;
+import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
import org.openapitools.codegen.languages.features.DocumentationProviderFeatures;
import org.openapitools.codegen.languages.features.SwaggerUIFeatures;
-import org.openapitools.codegen.meta.features.*;
+import org.openapitools.codegen.meta.features.DocumentationFeature;
+import org.openapitools.codegen.meta.features.GlobalFeature;
+import org.openapitools.codegen.meta.features.ParameterFeature;
+import org.openapitools.codegen.meta.features.SchemaSupportFeature;
+import org.openapitools.codegen.meta.features.SecurityFeature;
+import org.openapitools.codegen.meta.features.WireFormatFeature;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.model.OperationMap;
@@ -39,7 +52,14 @@ import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.regex.Matcher;
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
@@ -58,10 +78,15 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
"ApiResponse"
));
+ public static final String OPEN_BRACE = "{";
+ public static final String CLOSE_BRACE = "}";
+
public static final String TITLE = "title";
public static final String SERVER_PORT = "serverPort";
+ public static final String CONFIG_PACKAGE = "configPackage";
public static final String BASE_PACKAGE = "basePackage";
public static final String SPRING_BOOT = "spring-boot";
+ public static final String SPRING_CLOUD_LIBRARY = "spring-cloud";
public static final String EXCEPTION_HANDLER = "exceptionHandler";
public static final String GRADLE_BUILD_FILE = "gradleBuildFile";
public static final String SERVICE_INTERFACE = "serviceInterface";
@@ -69,6 +94,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
public static final String SKIP_DEFAULT_INTERFACE = "skipDefaultInterface";
public static final String REACTIVE = "reactive";
public static final String INTERFACE_ONLY = "interfaceOnly";
+ public static final String USE_FEIGN_CLIENT_URL = "useFeignClientUrl";
public static final String DELEGATE_PATTERN = "delegatePattern";
public static final String USE_TAGS = "useTags";
public static final String BEAN_QUALIFIERS = "beanQualifiers";
@@ -76,6 +102,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
public static final String USE_SPRING_BOOT3 = "useSpringBoot3";
private String basePackage;
+ protected String configPackage;
private String invokerPackage;
private String serverPort = "8080";
private String title = "OpenAPI Kotlin Spring";
@@ -88,6 +115,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
private boolean serviceImplementation = false;
private boolean reactive = false;
private boolean interfaceOnly = false;
+ protected boolean useFeignClientUrl = true;
private boolean delegatePattern = false;
protected boolean useTags = false;
private boolean beanQualifiers = false;
@@ -128,12 +156,16 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
artifactId = "openapi-spring";
basePackage = invokerPackage = "org.openapitools";
+ configPackage = "org.openapitools.configuration";
apiPackage = "org.openapitools.api";
modelPackage = "org.openapitools.model";
// cliOptions default redefinition need to be updated
updateOption(CodegenConstants.ARTIFACT_ID, this.artifactId);
+ additionalProperties.put("openbrace", OPEN_BRACE);
+ additionalProperties.put("closebrace", CLOSE_BRACE);
+
// Use lists instead of arrays
typeMapping.put("array", "kotlin.collections.List");
typeMapping.put("list", "kotlin.collections.List");
@@ -142,6 +174,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
typeMapping.put("file", "org.springframework.core.io.Resource");
addOption(TITLE, "server title name or client service name", title);
+ addOption(CONFIG_PACKAGE, "configuration package for generated code", this.getConfigPackage());
addOption(BASE_PACKAGE, "base package (invokerPackage) 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);
@@ -158,6 +191,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
addSwitch(SKIP_DEFAULT_INTERFACE, "Whether to skip generation of default implementations for interfaces", skipDefaultInterface);
addSwitch(REACTIVE, "use coroutines for reactive behavior", reactive);
addSwitch(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files.", interfaceOnly);
+ addSwitch(USE_FEIGN_CLIENT_URL, "Whether to generate Feign client with url parameter.", useFeignClientUrl);
addSwitch(DELEGATE_PATTERN, "Whether to generate the server files using the delegate pattern", delegatePattern);
addSwitch(USE_TAGS, "Whether to use tags for creating interface and controller class names", useTags);
addSwitch(BEAN_QUALIFIERS, "Whether to add fully-qualifier class names as bean qualifiers in @Component and " +
@@ -165,6 +199,8 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
" (contexts) added to single project.", beanQualifiers);
addSwitch(USE_SPRING_BOOT3, "Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.", useSpringBoot3);
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
+ supportedLibraries.put(SPRING_CLOUD_LIBRARY,
+ "Spring-Cloud-Feign client with Spring-Boot auto-configured settings.");
setLibrary(SPRING_BOOT);
CliOption cliOpt = new CliOption(CodegenConstants.LIBRARY, CodegenConstants.LIBRARY_DESC);
@@ -243,6 +279,14 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
getDocumentationProvider().equals(DocumentationProvider.SOURCE);
}
+ public void setConfigPackage(String configPackage) {
+ this.configPackage = configPackage;
+ }
+
+ public String getConfigPackage() {
+ return configPackage;
+ }
+
public String getBasePackage() {
return this.basePackage;
}
@@ -300,6 +344,10 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
this.serviceInterface = serviceInterface;
}
+ public void setUseFeignClientUrl(boolean useFeignClientUrl) {
+ this.useFeignClientUrl = useFeignClientUrl;
+ }
+
public boolean getServiceImplementation() {
return this.serviceImplementation;
}
@@ -454,6 +502,12 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
LOGGER.info("Set base package to invoker package ({})", basePackage);
}
+ if (additionalProperties.containsKey(CONFIG_PACKAGE)) {
+ this.setConfigPackage((String) additionalProperties.get(CONFIG_PACKAGE));
+ } else {
+ additionalProperties.put(CONFIG_PACKAGE, configPackage);
+ }
+
if (additionalProperties.containsKey(BASE_PACKAGE)) {
this.setBasePackage((String) additionalProperties.get(BASE_PACKAGE));
} else {
@@ -504,10 +558,15 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
}
writePropertyBack(SKIP_DEFAULT_INTERFACE, skipDefaultInterface);
- if (additionalProperties.containsKey(REACTIVE) && library.equals(SPRING_BOOT)) {
- this.setReactive(convertPropertyToBoolean(REACTIVE));
- // spring webflux doesn't support @ControllerAdvice
- this.setExceptionHandler(false);
+ if (additionalProperties.containsKey(REACTIVE)) {
+ if (SPRING_CLOUD_LIBRARY.equals(library)) {
+ throw new IllegalArgumentException("Currently, reactive option doesn't supported by Spring Cloud");
+ }
+ if (library.equals(SPRING_BOOT)) {
+ this.setReactive(convertPropertyToBoolean(REACTIVE));
+ // spring webflux doesn't support @ControllerAdvice
+ this.setExceptionHandler(false);
+ }
}
writePropertyBack(REACTIVE, reactive);
writePropertyBack(EXCEPTION_HANDLER, exceptionHandler);
@@ -521,6 +580,15 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
this.setInterfaceOnly(Boolean.parseBoolean(additionalProperties.get(INTERFACE_ONLY).toString()));
}
+ if (library.equals(SPRING_CLOUD_LIBRARY)) {
+ this.setInterfaceOnly(true);
+ }
+
+ if (additionalProperties.containsKey(USE_FEIGN_CLIENT_URL)) {
+ this.setUseFeignClientUrl(Boolean.parseBoolean(additionalProperties.get(USE_FEIGN_CLIENT_URL).toString()));
+ }
+ writePropertyBack(USE_FEIGN_CLIENT_URL, useFeignClientUrl);
+
if (additionalProperties.containsKey(DELEGATE_PATTERN)) {
this.setDelegatePattern(Boolean.parseBoolean(additionalProperties.get(DELEGATE_PATTERN).toString()));
}
@@ -557,11 +625,6 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
apiTestTemplateFiles.put("api_test.mustache", ".kt");
}
- if (SPRING_BOOT.equals(library)) {
- supportingFiles.add(new SupportingFile("apiUtil.mustache",
- (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiUtil.kt"));
- }
-
if (this.serviceInterface) {
apiTemplateFiles.put("service.mustache", "Service.kt");
} else if (this.serviceImplementation) {
@@ -579,13 +642,17 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
- if (this.exceptionHandler) {
+ if (this.exceptionHandler && !library.equals(SPRING_CLOUD_LIBRARY)) {
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("apiUtil.mustache",
+ (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiUtil.kt"));
+
if (isUseSpringBoot3()) {
supportingFiles.add(new SupportingFile("pom-sb3.mustache", "", "pom.xml"));
} else {
@@ -621,7 +688,36 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
}
}
- if (!reactive) {
+ if (library.equals(SPRING_CLOUD_LIBRARY)) {
+ LOGGER.info("Setup code generator for Kotlin Spring Cloud Client");
+
+ if (isUseSpringBoot3()) {
+ supportingFiles.add(new SupportingFile("pom-sb3.mustache", "pom.xml"));
+ } else {
+ supportingFiles.add(new SupportingFile("pom.mustache", "pom.xml"));
+ }
+
+ if (this.gradleBuildFile) {
+ if (isUseSpringBoot3()) {
+ supportingFiles.add(new SupportingFile("buildGradle-sb3-Kts.mustache", "build.gradle.kts"));
+ } else {
+ supportingFiles.add(new SupportingFile("buildGradleKts.mustache", "build.gradle.kts"));
+ }
+ supportingFiles.add(new SupportingFile("settingsGradle.mustache", "settings.gradle"));
+ }
+
+ supportingFiles.add(new SupportingFile("apiKeyRequestInterceptor.mustache",
+ (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
+ "ApiKeyRequestInterceptor.kt"));
+ supportingFiles.add(new SupportingFile("clientConfiguration.mustache",
+ (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
+ "ClientConfiguration.kt"));
+ apiTemplateFiles.put("apiClient.mustache", "Client.kt");
+
+ apiTestTemplateFiles.clear();
+ }
+
+ if (!reactive && !library.equals(SPRING_CLOUD_LIBRARY)) {
if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) {
supportingFiles.add(new SupportingFile("springfoxDocumentationConfig.mustache",
(sourceFolder + File.separator + basePackage).replace(".", java.io.File.separator),
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/README.mustache
new file mode 100644
index 00000000000..3550f428c71
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/README.mustache
@@ -0,0 +1,83 @@
+{{^interfaceOnly}}
+# {{artifactId}}
+
+## Requirements
+
+Building the API client library requires [Maven](https://maven.apache.org/) to be installed.
+
+## Installation
+
+To install the API client library to your local Maven repository, simply execute:
+
+```shell
+mvn install
+```
+
+To deploy it to a remote Maven repository instead, configure the settings of the repository and execute:
+
+```shell
+mvn deploy
+```
+
+Refer to the [official documentation](https://maven.apache.org/plugins/maven-deploy-plugin/usage.html) for more information.
+
+### Maven users
+
+Add this dependency to your project's POM:
+
+```xml
+
+ {{{groupId}}}
+ {{{artifactId}}}
+ {{{artifactVersion}}}
+ compile
+
+```
+
+### Gradle users
+
+Add this dependency to your project's build file:
+
+```groovy
+compile "{{{groupId}}}:{{{artifactId}}}:{{{artifactVersion}}}"
+```
+
+### Others
+
+At first generate the JAR by executing:
+
+mvn package
+
+Then manually install the following JARs:
+
+* target/{{{artifactId}}}-{{{artifactVersion}}}.jar
+* target/lib/*.jar
+{{/interfaceOnly}}
+{{#interfaceOnly}}
+# OpenAPI generated API stub
+
+Spring Framework stub
+
+
+## Overview
+This code was generated by the [OpenAPI Generator](https://openapi-generator.tech) project.
+By using the [OpenAPI-Spec](https://openapis.org), you can easily generate an API stub.
+This is an example of building API stub interfaces in Java using the Spring framework.
+
+The stubs generated can be used in your existing Spring-MVC or Spring-Boot application to create controller endpoints
+by adding ```@Controller``` classes that implement the interface. Eg:
+```java
+@Controller
+public class PetController implements PetApi {
+// implement all PetApi methods
+}
+```
+
+You can also use the interface to create [Spring-Cloud Feign clients](http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign-inheritance).Eg:
+```java
+@FeignClient(name="pet", url="http://petstore.swagger.io/v2")
+public interface PetClient extends PetApi {
+
+}
+```
+{{/interfaceOnly}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/apiClient.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/apiClient.mustache
new file mode 100644
index 00000000000..e900e8b5357
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/apiClient.mustache
@@ -0,0 +1,11 @@
+package {{package}}
+
+import org.springframework.cloud.openfeign.FeignClient
+import {{configPackage}}.ClientConfiguration
+
+@FeignClient(
+ name="\${{openbrace}}{{classVarName}}.name:{{classVarName}}{{closebrace}}",
+ {{#useFeignClientUrl}}url="\${{openbrace}}{{classVarName}}.url:{{basePath}}{{closebrace}}", {{/useFeignClientUrl}}
+ configuration = [ClientConfiguration::class]
+)
+interface {{classname}}Client : {{classname}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/apiKeyRequestInterceptor.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/apiKeyRequestInterceptor.mustache
new file mode 100644
index 00000000000..86bd615ccae
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/apiKeyRequestInterceptor.mustache
@@ -0,0 +1,19 @@
+package {{configPackage}}
+
+import feign.RequestInterceptor
+import feign.RequestTemplate
+
+class ApiKeyRequestInterceptor(
+ private val location: String,
+ private val name: String,
+ private val value: String,
+) : RequestInterceptor {
+
+ override fun apply(requestTemplate: RequestTemplate) {
+ if (location == "header") {
+ requestTemplate.header(name, value)
+ } else if (location == "query") {
+ requestTemplate.query(name, value)
+ }
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/buildGradle-sb3-Kts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/buildGradle-sb3-Kts.mustache
new file mode 100644
index 00000000000..1bf4d313066
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/buildGradle-sb3-Kts.mustache
@@ -0,0 +1,68 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+group = "{{groupId}}"
+version = "{{artifactVersion}}"
+java.sourceCompatibility = JavaVersion.VERSION_17
+
+repositories {
+ mavenCentral()
+ maven { url = uri("https://repo.spring.io/milestone") }
+}
+
+tasks.withType {
+ kotlinOptions.jvmTarget = "17"
+}
+
+plugins {
+ val kotlinVersion = "1.7.10"
+ 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 "3.0.2"
+ id("io.spring.dependency-management") version "1.0.14.RELEASE"
+}
+
+tasks.getByName("bootJar") {
+ enabled = false
+}
+
+tasks.getByName("jar") {
+ enabled = true
+}
+
+dependencyManagement {
+ imports {
+ mavenBom("org.springframework.cloud:spring-cloud-dependencies:2021.0.5")
+ }
+}
+
+dependencies {
+{{#reactive}} val kotlinxCoroutinesVersion = "1.6.1"
+{{/reactive}} implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
+ implementation("org.jetbrains.kotlin:kotlin-reflect"){{^reactive}}
+ implementation("org.springframework.boot:spring-boot-starter-web"){{/reactive}}{{#reactive}}
+ implementation("org.springframework.boot:spring-boot-starter-webflux")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion"){{/reactive}}{{#springDocDocumentationProvider}}{{#useSwaggerUI}}
+ implementation("org.springdoc:springdoc-openapi-starter-{{#reactive}}webflux{{/reactive}}{{^reactive}}webmvc{{/reactive}}-ui:2.0.0-M5"){{/useSwaggerUI}}{{^useSwaggerUI}}
+ implementation("org.springdoc:springdoc-openapi-{{#reactive}}webflux{{/reactive}}{{^reactive}}webmvc{{/reactive}}-core:2.0.0-M5"){{/useSwaggerUI}}{{/springDocDocumentationProvider}}{{#springFoxDocumentationProvider}}
+ implementation("io.springfox:springfox-swagger2:2.9.2"){{/springFoxDocumentationProvider}}{{#useSwaggerUI}}{{^springDocDocumentationProvider}}
+ implementation("org.webjars:swagger-ui:4.10.3")
+ implementation("org.webjars:webjars-locator-core"){{/springDocDocumentationProvider}}{{/useSwaggerUI}}{{^springFoxDocumentationProvider}}{{^springDocDocumentationProvider}}{{#swagger1AnnotationLibrary}}
+ implementation("io.swagger:swagger-annotations:1.6.6"){{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}
+ implementation("io.swagger.core.v3:swagger-annotations:2.2.0"){{/swagger2AnnotationLibrary}}{{/springDocDocumentationProvider}}{{/springFoxDocumentationProvider}}
+
+ implementation("com.google.code.findbugs:jsr305:3.0.2")
+ implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml")
+ implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
+ implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
+
+ implementation("org.springframework.cloud:spring-cloud-starter-openfeign"){{#hasAuthMethods}}
+ implementation("org.springframework.cloud:spring-cloud-starter-oauth2:2.2.5.RELEASE"){{/hasAuthMethods}}
+
+{{#useBeanValidation}}
+ implementation("jakarta.validation:jakarta.validation-api"){{/useBeanValidation}}
+ implementation("jakarta.annotation:jakarta.annotation-api:2.1.0")
+
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/buildGradleKts.mustache
new file mode 100644
index 00000000000..b1a7e08ce4b
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/buildGradleKts.mustache
@@ -0,0 +1,75 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:2.6.7")
+ }
+}
+
+group = "{{groupId}}"
+version = "{{artifactVersion}}"
+
+repositories {
+ mavenCentral()
+}
+
+tasks.withType {
+ kotlinOptions.jvmTarget = "1.8"
+}
+
+plugins {
+ val kotlinVersion = "1.6.21"
+ 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.6.7"
+ id("io.spring.dependency-management") version "1.0.11.RELEASE"
+}
+
+tasks.getByName("bootJar") {
+ enabled = false
+}
+
+tasks.getByName("jar") {
+ enabled = true
+}
+
+dependencyManagement {
+ imports {
+ mavenBom("org.springframework.cloud:spring-cloud-dependencies:2021.0.5")
+ }
+}
+
+dependencies {
+{{#reactive}} val kotlinxCoroutinesVersion = "1.6.1"
+{{/reactive}} implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
+ implementation("org.jetbrains.kotlin:kotlin-reflect"){{^reactive}}
+ implementation("org.springframework.boot:spring-boot-starter-web"){{/reactive}}{{#reactive}}
+ implementation("org.springframework.boot:spring-boot-starter-webflux")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion"){{/reactive}}{{#springDocDocumentationProvider}}{{#useSwaggerUI}}
+ implementation("org.springdoc:springdoc-openapi-{{#reactive}}webflux-{{/reactive}}ui:1.6.8"){{/useSwaggerUI}}{{^useSwaggerUI}}
+ implementation("org.springdoc:springdoc-openapi-{{#reactive}}webflux{{/reactive}}{{^reactive}}webmvc{{/reactive}}-core:1.6.8"){{/useSwaggerUI}}{{/springDocDocumentationProvider}}{{#springFoxDocumentationProvider}}
+ implementation("io.springfox:springfox-swagger2:2.9.2"){{/springFoxDocumentationProvider}}{{#useSwaggerUI}}{{^springDocDocumentationProvider}}
+ implementation("org.webjars:swagger-ui:4.10.3")
+ implementation("org.webjars:webjars-locator-core"){{/springDocDocumentationProvider}}{{/useSwaggerUI}}{{^springFoxDocumentationProvider}}{{^springDocDocumentationProvider}}{{#swagger1AnnotationLibrary}}
+ implementation("io.swagger:swagger-annotations:1.6.6"){{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}
+ implementation("io.swagger.core.v3:swagger-annotations:2.2.0"){{/swagger2AnnotationLibrary}}{{/springDocDocumentationProvider}}{{/springFoxDocumentationProvider}}
+
+ implementation("com.google.code.findbugs:jsr305:3.0.2")
+ implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml")
+ implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
+ implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
+
+ implementation("org.springframework.cloud:spring-cloud-starter-openfeign"){{#hasAuthMethods}}
+ implementation("org.springframework.cloud:spring-cloud-starter-oauth2:2.2.5.RELEASE"){{/hasAuthMethods}}
+
+{{#useBeanValidation}}
+ implementation("jakarta.validation:jakarta.validation-api"){{/useBeanValidation}}
+ implementation("jakarta.annotation:jakarta.annotation-api:2.1.0")
+
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/clientConfiguration.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/clientConfiguration.mustache
new file mode 100644
index 00000000000..c23c5ee1237
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/clientConfiguration.mustache
@@ -0,0 +1,132 @@
+package {{configPackage}}
+
+{{#authMethods}}
+{{#isBasic}}
+import feign.auth.BasicAuthRequestInterceptor
+{{/isBasic}}
+{{#-first}}
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
+{{/-first}}
+{{#isOAuth}}
+import org.springframework.boot.context.properties.ConfigurationProperties
+{{/isOAuth}}
+{{/authMethods}}
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+{{#authMethods}}
+{{#-first}}
+import org.springframework.context.annotation.Bean
+{{/-first}}
+{{/authMethods}}
+import org.springframework.context.annotation.Configuration
+{{#authMethods}}
+{{#isOAuth}}
+import org.springframework.cloud.openfeign.security.OAuth2FeignRequestInterceptor
+import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext
+import org.springframework.security.oauth2.client.OAuth2ClientContext
+{{#isApplication}}
+import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails
+{{/isApplication}}
+{{#isCode}}
+import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails
+{{/isCode}}
+{{#isImplicit}}
+import org.springframework.security.oauth2.client.token.grant.implicit.ImplicitResourceDetails
+{{/isImplicit}}
+{{#isPassword}}
+import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails
+{{/isPassword}}
+{{/isOAuth}}
+{{/authMethods}}
+
+@Configuration
+@EnableConfigurationProperties
+class ClientConfiguration {
+
+ {{#authMethods}}
+ {{#isBasic}}
+ @Value("\${{openbrace}}{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.username:{{closebrace}}")
+ private lateinit var {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}Username: String
+
+ @Value("\${{openbrace}}{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.password:{{closebrace}}")
+ private lateinit var {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}Password: String
+
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.username")
+ fun {{{name}}}RequestInterceptor(): BasicAuthRequestInterceptor {
+ return BasicAuthRequestInterceptor(this.{{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}Username, this.{{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}Password)
+ }
+
+ {{/isBasic}}
+ {{#isApiKey}}
+ @Value("\${{openbrace}}{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.key:{{closebrace}}")
+ private lateinit var {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}Key: String
+
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.key")
+ fun {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}RequestInterceptor(): ApiKeyRequestInterceptor {
+ return ApiKeyRequestInterceptor({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{{keyParamName}}}", this.{{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}Key)
+ }
+
+ {{/isApiKey}}
+ {{#isOAuth}}
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
+ fun {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}RequestInterceptor(oAuth2ClientContext: OAuth2ClientContext): OAuth2FeignRequestInterceptor {
+ return OAuth2FeignRequestInterceptor(oAuth2ClientContext, {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}ResourceDetails())
+ }
+
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
+ fun oAuth2ClientContext(): OAuth2ClientContext {
+ return DefaultOAuth2ClientContext()
+ }
+
+ {{#isCode}}
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
+ @ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
+ fun {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}ResourceDetails(): AuthorizationCodeResourceDetails {
+ val details = AuthorizationCodeResourceDetails()
+ details.accessTokenUri = "{{{tokenUrl}}}"
+ details.userAuthorizationUri = "{{{authorizationUrl}}}"
+ return details
+ }
+
+ {{/isCode}}
+ {{#isPassword}}
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
+ @ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
+ fun {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}ResourceDetails(): ResourceOwnerPasswordResourceDetails {
+ val details = ResourceOwnerPasswordResourceDetails()
+ details.accessTokenUri = "{{{tokenUrl}}}"
+ return details
+ }
+
+ {{/isPassword}}
+ {{#isApplication}}
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
+ @ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
+ fun {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}ResourceDetails(): ClientCredentialsResourceDetails {
+ val details = ClientCredentialsResourceDetails()
+ details.accessTokenUri = "{{{tokenUrl}}}"
+ return details
+ }
+
+ {{/isApplication}}
+ {{#isImplicit}}
+ @Bean
+ @ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
+ @ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
+ fun {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}ResourceDetails(): ImplicitResourceDetails {
+ val details = ImplicitResourceDetails()
+ details.userAuthorizationUri= "{{{authorizationUrl}}}"
+ return details
+ }
+
+ {{/isImplicit}}
+ {{/isOAuth}}
+ {{/authMethods}}
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/pom-sb3.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/pom-sb3.mustache
new file mode 100644
index 00000000000..14621302900
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/pom-sb3.mustache
@@ -0,0 +1,233 @@
+
+ 4.0.0
+ {{groupId}}
+ {{artifactId}}
+ jar
+ {{artifactId}}
+ {{artifactVersion}}
+ {{#reactive}}
+ 1.6.1
+ {{/reactive}}{{#springDocDocumentationProvider}}{{#useSwaggerUI}}
+ 2.0.2
+ {{/useSwaggerUI}}{{/springDocDocumentationProvider}}{{#springFoxDocumentationProvider}}
+ 2.9.2
+ {{/springFoxDocumentationProvider}}{{#useSwaggerUI}}{{^springDocDocumentationProvider}}
+ 4.15.5
+ {{/springDocDocumentationProvider}}{{/useSwaggerUI}}{{^springFoxDocumentationProvider}}{{^springDocDocumentationProvider}}{{#swagger1AnnotationLibrary}}
+ 1.6.6
+ {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}
+ 2.2.7
+ {{/swagger2AnnotationLibrary}}{{/springDocDocumentationProvider}}{{/springFoxDocumentationProvider}}
+ 3.0.2
+ 2.1.0
+ 1.7.10
+
+ 1.7.10
+ UTF-8
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.2
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-parent
+ 2021.0.5
+ pom
+ import
+
+
+
+
+
+ repository.spring.milestone
+ Spring Milestone Repository
+ https://repo.spring.io/milestone
+
+
+
+
+ spring-milestones
+ https://repo.spring.io/milestone
+
+
+
+ ${project.basedir}/src/main/kotlin
+ {{^interfaceOnly}}
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+ {{/interfaceOnly}}
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ ${kotlin.version}
+
+
+ spring
+
+ 17
+
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-allopen
+ ${kotlin.version}
+
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ ${kotlin.version}
+ {{^reactive}}
+
+ org.springframework.boot
+ spring-boot-starter-web
+ {{/reactive}}{{#reactive}}
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.jetbrains.kotlinx
+ kotlinx-coroutines-core
+ ${kotlinx-coroutines.version}
+
+
+ org.jetbrains.kotlinx
+ kotlinx-coroutines-reactor
+ ${kotlinx-coroutines.version}
+ {{/reactive}}
+
+ {{#springDocDocumentationProvider}}
+ {{#useSwaggerUI}}
+
+ org.springdoc
+ springdoc-openapi-starter-{{#reactive}}
+ webflux{{/reactive}}{{^reactive}}webmvc{{/reactive}}-ui
+
+ ${springdoc-openapi.version}
+ {{/useSwaggerUI}}{{^useSwaggerUI}}
+
+ org.springdoc
+ springdoc-openapi-{{#reactive}}webflux{{/reactive}}{{^reactive}}webmvc{{/reactive}}-core
+
+ ${springdoc-openapi.version}
+ {{/useSwaggerUI}}{{/springDocDocumentationProvider}}{{#springFoxDocumentationProvider}}
+
+
+ io.springfox
+ springfox-swagger2
+ ${springfox-swagger2.version}
+ {{/springFoxDocumentationProvider}}{{#useSwaggerUI}}{{^springDocDocumentationProvider}}
+
+ org.webjars
+ swagger-ui
+ ${swagger-ui.version}
+
+
+ org.webjars
+ webjars-locator-core
+ {{/springDocDocumentationProvider}}{{/useSwaggerUI}}{{^springFoxDocumentationProvider}}{{^springDocDocumentationProvider}}{{#swagger1AnnotationLibrary}}
+
+ io.swagger
+ swagger-annotations
+ ${swagger-annotations.version}
+ {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}
+
+ io.swagger.core.v3
+ swagger-annotations
+ ${swagger-annotations.version}
+ {{/swagger2AnnotationLibrary}}{{/springDocDocumentationProvider}}{{/springFoxDocumentationProvider}}
+
+
+
+ com.google.code.findbugs
+ jsr305
+ ${findbugs-jsr305.version}
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+ {{#hasAuthMethods}}
+
+ org.springframework.cloud
+ spring-cloud-starter-oauth2
+ {{^parentOverridden}}
+ 2.2.5.RELEASE
+ {{/parentOverridden}}
+
+ {{/hasAuthMethods}}
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+ com.fasterxml.jackson.module
+ jackson-module-kotlin
+
+{{#useBeanValidation}}
+
+
+ jakarta.validation
+ jakarta.validation-api
+ {{/useBeanValidation}}
+
+ jakarta.annotation
+ jakarta.annotation-api
+ ${jakarta-annotation.version}
+ provided
+
+
+ org.jetbrains.kotlin
+ kotlin-test-junit5
+ ${kotlin-test-junit5.version}
+ test
+
+
+
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/pom.mustache
new file mode 100644
index 00000000000..ddab15182b6
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/pom.mustache
@@ -0,0 +1,210 @@
+
+ 4.0.0
+ {{groupId}}
+ {{artifactId}}
+ jar
+ {{artifactId}}
+ {{artifactVersion}}
+ {{#reactive}}
+ 1.6.1{{/reactive}}{{#springDocDocumentationProvider}}{{#useSwaggerUI}}
+ 1.6.8{{/useSwaggerUI}}{{/springDocDocumentationProvider}}{{#springFoxDocumentationProvider}}
+ 2.9.2{{/springFoxDocumentationProvider}}{{#useSwaggerUI}}{{^springDocDocumentationProvider}}
+ 4.10.3{{/springDocDocumentationProvider}}{{/useSwaggerUI}}{{^springFoxDocumentationProvider}}{{^springDocDocumentationProvider}}{{#swagger1AnnotationLibrary}}
+ 1.6.6{{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}
+ 2.2.0{{/swagger2AnnotationLibrary}}{{/springDocDocumentationProvider}}{{/springFoxDocumentationProvider}}
+ 3.0.2
+ 2.1.0
+ 1.6.21
+
+ 1.6.21
+ UTF-8
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.7
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-parent
+ 2021.0.5
+ pom
+ import
+
+
+
+
+ ${project.basedir}/src/main/kotlin
+ {{^interfaceOnly}}
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+ {{/interfaceOnly}}
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ ${kotlin.version}
+
+
+ spring
+
+ 1.8
+
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-allopen
+ ${kotlin.version}
+
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ ${kotlin.version}
+ {{^reactive}}
+
+ org.springframework.boot
+ spring-boot-starter-web
+ {{/reactive}}{{#reactive}}
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.jetbrains.kotlinx
+ kotlinx-coroutines-core
+ ${kotlinx-coroutines.version}
+
+
+ org.jetbrains.kotlinx
+ kotlinx-coroutines-reactor
+ ${kotlinx-coroutines.version}
+ {{/reactive}}
+
+{{#springDocDocumentationProvider}}
+ {{#useSwaggerUI}}
+
+ org.springdoc
+ springdoc-openapi-{{#reactive}}webflux-{{/reactive}}ui
+ ${springdoc-openapi.version}
+ {{/useSwaggerUI}}{{^useSwaggerUI}}
+
+ org.springdoc
+ springdoc-openapi-{{#reactive}}webflux{{/reactive}}{{^reactive}}webmvc{{/reactive}}-core
+ ${springdoc-openapi.version}
+ {{/useSwaggerUI}}{{/springDocDocumentationProvider}}{{#springFoxDocumentationProvider}}
+
+
+ io.springfox
+ springfox-swagger2
+ ${springfox-swagger2.version}
+ {{/springFoxDocumentationProvider}}{{#useSwaggerUI}}{{^springDocDocumentationProvider}}
+
+ org.webjars
+ swagger-ui
+ ${swagger-ui.version}
+
+
+ org.webjars
+ webjars-locator-core
+ {{/springDocDocumentationProvider}}{{/useSwaggerUI}}{{^springFoxDocumentationProvider}}{{^springDocDocumentationProvider}}{{#swagger1AnnotationLibrary}}
+
+ io.swagger
+ swagger-annotations
+ ${swagger-annotations.version}
+ {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}
+
+ io.swagger.core.v3
+ swagger-annotations
+ ${swagger-annotations.version}
+ {{/swagger2AnnotationLibrary}}{{/springDocDocumentationProvider}}{{/springFoxDocumentationProvider}}
+
+
+
+ com.google.code.findbugs
+ jsr305
+ ${findbugs-jsr305.version}
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+ {{#hasAuthMethods}}
+
+ org.springframework.cloud
+ spring-cloud-starter-oauth2
+ {{^parentOverridden}}
+ 2.2.5.RELEASE
+ {{/parentOverridden}}
+
+ {{/hasAuthMethods}}
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+ com.fasterxml.jackson.module
+ jackson-module-kotlin
+
+{{#useBeanValidation}}
+
+
+ jakarta.validation
+ jakarta.validation-api
+ {{/useBeanValidation}}
+
+ jakarta.annotation
+ jakarta.annotation-api
+ ${jakarta-annotation.version}
+ provided
+
+
+ org.jetbrains.kotlin
+ kotlin-test-junit5
+ ${kotlin-test-junit5.version}
+ test
+
+
+
diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/settingsGradle.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/settingsGradle.mustache
new file mode 100644
index 00000000000..fd23a36b903
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/settingsGradle.mustache
@@ -0,0 +1,15 @@
+pluginManagement {
+ repositories {
+ maven { url = uri("https://repo.spring.io/snapshot") }
+ maven { url = uri("https://repo.spring.io/milestone") }
+ gradlePluginPortal()
+ }
+ resolutionStrategy {
+ eachPlugin {
+ if (requested.id.id == "org.springframework.boot") {
+ useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}")
+ }
+ }
+ }
+}
+rootProject.name = "{{artifactId}}"
diff --git a/samples/client/petstore/kotlin-spring-cloud/.openapi-generator-ignore b/samples/client/petstore/kotlin-spring-cloud/.openapi-generator-ignore
new file mode 100644
index 00000000000..7484ee590a3
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/.openapi-generator-ignore
@@ -0,0 +1,23 @@
+# OpenAPI Generator Ignore
+# Generated by openapi-generator https://github.com/openapitools/openapi-generator
+
+# Use this file to prevent files from being overwritten by the generator.
+# The patterns follow closely to .gitignore or .dockerignore.
+
+# As an example, the C# client generator defines ApiClient.cs.
+# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
+#ApiClient.cs
+
+# You can match any string of characters against a directory, file or extension with a single asterisk (*):
+#foo/*/qux
+# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
+
+# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
+#foo/**/qux
+# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
+
+# You can also negate patterns with an exclamation (!).
+# For example, you can ignore all files in a docs folder with the file extension .md:
+#docs/*.md
+# Then explicitly reverse the ignore rule for a single file:
+#!docs/README.md
diff --git a/samples/client/petstore/kotlin-spring-cloud/.openapi-generator/FILES b/samples/client/petstore/kotlin-spring-cloud/.openapi-generator/FILES
new file mode 100644
index 00000000000..cb11aec76f7
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/.openapi-generator/FILES
@@ -0,0 +1,18 @@
+README.md
+build.gradle.kts
+pom.xml
+settings.gradle
+src/main/kotlin/org/openapitools/api/PetApi.kt
+src/main/kotlin/org/openapitools/api/PetApiClient.kt
+src/main/kotlin/org/openapitools/api/StoreApi.kt
+src/main/kotlin/org/openapitools/api/StoreApiClient.kt
+src/main/kotlin/org/openapitools/api/UserApi.kt
+src/main/kotlin/org/openapitools/api/UserApiClient.kt
+src/main/kotlin/org/openapitools/configuration/ApiKeyRequestInterceptor.kt
+src/main/kotlin/org/openapitools/configuration/ClientConfiguration.kt
+src/main/kotlin/org/openapitools/model/Category.kt
+src/main/kotlin/org/openapitools/model/ModelApiResponse.kt
+src/main/kotlin/org/openapitools/model/Order.kt
+src/main/kotlin/org/openapitools/model/Pet.kt
+src/main/kotlin/org/openapitools/model/Tag.kt
+src/main/kotlin/org/openapitools/model/User.kt
diff --git a/samples/client/petstore/kotlin-spring-cloud/.openapi-generator/VERSION b/samples/client/petstore/kotlin-spring-cloud/.openapi-generator/VERSION
new file mode 100644
index 00000000000..ba8a874deab
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/.openapi-generator/VERSION
@@ -0,0 +1 @@
+6.6.0-SNAPSHOT
\ No newline at end of file
diff --git a/samples/client/petstore/kotlin-spring-cloud/README.md b/samples/client/petstore/kotlin-spring-cloud/README.md
new file mode 100644
index 00000000000..a462be951ac
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/README.md
@@ -0,0 +1,26 @@
+# OpenAPI generated API stub
+
+Spring Framework stub
+
+
+## Overview
+This code was generated by the [OpenAPI Generator](https://openapi-generator.tech) project.
+By using the [OpenAPI-Spec](https://openapis.org), you can easily generate an API stub.
+This is an example of building API stub interfaces in Java using the Spring framework.
+
+The stubs generated can be used in your existing Spring-MVC or Spring-Boot application to create controller endpoints
+by adding ```@Controller``` classes that implement the interface. Eg:
+```java
+@Controller
+public class PetController implements PetApi {
+// implement all PetApi methods
+}
+```
+
+You can also use the interface to create [Spring-Cloud Feign clients](http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign-inheritance).Eg:
+```java
+@FeignClient(name="pet", url="http://petstore.swagger.io/v2")
+public interface PetClient extends PetApi {
+
+}
+```
diff --git a/samples/client/petstore/kotlin-spring-cloud/build.gradle.kts b/samples/client/petstore/kotlin-spring-cloud/build.gradle.kts
new file mode 100644
index 00000000000..b2c90c440cf
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/build.gradle.kts
@@ -0,0 +1,63 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:2.6.7")
+ }
+}
+
+group = "org.openapitools"
+version = "1.0.0"
+
+repositories {
+ mavenCentral()
+}
+
+tasks.withType {
+ kotlinOptions.jvmTarget = "1.8"
+}
+
+plugins {
+ val kotlinVersion = "1.6.21"
+ 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.6.7"
+ id("io.spring.dependency-management") version "1.0.11.RELEASE"
+}
+
+tasks.getByName("bootJar") {
+ enabled = false
+}
+
+tasks.getByName("jar") {
+ enabled = true
+}
+
+dependencyManagement {
+ imports {
+ mavenBom("org.springframework.cloud:spring-cloud-dependencies:2021.0.5")
+ }
+}
+
+dependencies {
+ implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
+ implementation("org.jetbrains.kotlin:kotlin-reflect")
+ implementation("org.springframework.boot:spring-boot-starter-web")
+
+ implementation("com.google.code.findbugs:jsr305:3.0.2")
+ implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml")
+ implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
+ implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
+
+ implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
+ implementation("org.springframework.cloud:spring-cloud-starter-oauth2:2.2.5.RELEASE")
+
+ implementation("jakarta.validation:jakarta.validation-api")
+ implementation("jakarta.annotation:jakarta.annotation-api:2.1.0")
+
+}
diff --git a/samples/client/petstore/kotlin-spring-cloud/pom.xml b/samples/client/petstore/kotlin-spring-cloud/pom.xml
new file mode 100644
index 00000000000..9f53a2f0ae0
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/pom.xml
@@ -0,0 +1,138 @@
+
+ 4.0.0
+ org.openapitools
+ openapi-spring
+ jar
+ openapi-spring
+ 1.0.0
+
+ 3.0.2
+ 2.1.0
+ 1.6.21
+
+ 1.6.21
+ UTF-8
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.7
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-parent
+ 2021.0.5
+ pom
+ import
+
+
+
+
+ ${project.basedir}/src/main/kotlin
+
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ ${kotlin.version}
+
+
+ spring
+
+ 1.8
+
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-allopen
+ ${kotlin.version}
+
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ ${kotlin.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+ com.google.code.findbugs
+ jsr305
+ ${findbugs-jsr305.version}
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.springframework.cloud
+ spring-cloud-starter-oauth2
+ 2.2.5.RELEASE
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+ com.fasterxml.jackson.module
+ jackson-module-kotlin
+
+
+
+ jakarta.validation
+ jakarta.validation-api
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+ ${jakarta-annotation.version}
+ provided
+
+
+ org.jetbrains.kotlin
+ kotlin-test-junit5
+ ${kotlin-test-junit5.version}
+ test
+
+
+
diff --git a/samples/client/petstore/kotlin-spring-cloud/settings.gradle b/samples/client/petstore/kotlin-spring-cloud/settings.gradle
new file mode 100644
index 00000000000..14844905cd4
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/settings.gradle
@@ -0,0 +1,15 @@
+pluginManagement {
+ repositories {
+ maven { url = uri("https://repo.spring.io/snapshot") }
+ maven { url = uri("https://repo.spring.io/milestone") }
+ gradlePluginPortal()
+ }
+ resolutionStrategy {
+ eachPlugin {
+ if (requested.id.id == "org.springframework.boot") {
+ useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}")
+ }
+ }
+ }
+}
+rootProject.name = "openapi-spring"
diff --git a/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/PetApi.kt
new file mode 100644
index 00000000000..f6e5790f710
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/PetApi.kt
@@ -0,0 +1,117 @@
+/**
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (6.6.0-SNAPSHOT).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+*/
+package org.openapitools.api
+
+import org.openapitools.model.ModelApiResponse
+import org.openapitools.model.Pet
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.http.ResponseEntity
+
+import org.springframework.web.bind.annotation.*
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.context.request.NativeWebRequest
+import org.springframework.beans.factory.annotation.Autowired
+
+import javax.validation.constraints.DecimalMax
+import javax.validation.constraints.DecimalMin
+import javax.validation.constraints.Email
+import javax.validation.constraints.Max
+import javax.validation.constraints.Min
+import javax.validation.constraints.NotNull
+import javax.validation.constraints.Pattern
+import javax.validation.constraints.Size
+import javax.validation.Valid
+
+import kotlin.collections.List
+import kotlin.collections.Map
+
+@Validated
+@RequestMapping("\${api.base-path:/v2}")
+interface PetApi {
+
+
+ @RequestMapping(
+ method = [RequestMethod.POST],
+ value = ["/pet"],
+ produces = ["application/xml", "application/json"],
+ consumes = ["application/json", "application/xml"]
+ )
+ fun addPet( @Valid @RequestBody pet: Pet): ResponseEntity {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.DELETE],
+ value = ["/pet/{petId}"]
+ )
+ fun deletePet( @PathVariable("petId") petId: kotlin.Long, @RequestHeader(value = "api_key", required = false) apiKey: kotlin.String?): ResponseEntity {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.GET],
+ value = ["/pet/findByStatus"],
+ produces = ["application/xml", "application/json"]
+ )
+ fun findPetsByStatus(@NotNull @Valid @RequestParam(value = "status", required = true) status: kotlin.collections.List): ResponseEntity> {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.GET],
+ value = ["/pet/findByTags"],
+ produces = ["application/xml", "application/json"]
+ )
+ fun findPetsByTags(@NotNull @Valid @RequestParam(value = "tags", required = true) tags: kotlin.collections.List): ResponseEntity> {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.GET],
+ value = ["/pet/{petId}"],
+ produces = ["application/xml", "application/json"]
+ )
+ fun getPetById( @PathVariable("petId") petId: kotlin.Long): ResponseEntity {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.PUT],
+ value = ["/pet"],
+ produces = ["application/xml", "application/json"],
+ consumes = ["application/json", "application/xml"]
+ )
+ fun updatePet( @Valid @RequestBody pet: Pet): ResponseEntity {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.POST],
+ value = ["/pet/{petId}"],
+ consumes = ["application/x-www-form-urlencoded"]
+ )
+ fun updatePetWithForm( @PathVariable("petId") petId: kotlin.Long, @RequestParam(value = "name", required = false) name: kotlin.String? , @RequestParam(value = "status", required = false) status: kotlin.String? ): ResponseEntity {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.POST],
+ value = ["/pet/{petId}/uploadImage"],
+ produces = ["application/json"],
+ consumes = ["multipart/form-data"]
+ )
+ fun uploadFile( @PathVariable("petId") petId: kotlin.Long, @RequestParam(value = "additionalMetadata", required = false) additionalMetadata: kotlin.String? , @Valid @RequestPart("file") file: org.springframework.core.io.Resource?): ResponseEntity {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+}
diff --git a/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/PetApiClient.kt b/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/PetApiClient.kt
new file mode 100644
index 00000000000..8373f9aa939
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/PetApiClient.kt
@@ -0,0 +1,11 @@
+package org.openapitools.api
+
+import org.springframework.cloud.openfeign.FeignClient
+import org.openapitools.configuration.ClientConfiguration
+
+@FeignClient(
+ name="\${pet.name:pet}",
+ url="\${pet.url:http://petstore.swagger.io/v2}",
+ configuration = [ClientConfiguration::class]
+)
+interface PetApiClient : PetApi
diff --git a/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/StoreApi.kt b/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/StoreApi.kt
new file mode 100644
index 00000000000..a05822c7b3f
--- /dev/null
+++ b/samples/client/petstore/kotlin-spring-cloud/src/main/kotlin/org/openapitools/api/StoreApi.kt
@@ -0,0 +1,74 @@
+/**
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (6.6.0-SNAPSHOT).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+*/
+package org.openapitools.api
+
+import org.openapitools.model.Order
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.http.ResponseEntity
+
+import org.springframework.web.bind.annotation.*
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.context.request.NativeWebRequest
+import org.springframework.beans.factory.annotation.Autowired
+
+import javax.validation.constraints.DecimalMax
+import javax.validation.constraints.DecimalMin
+import javax.validation.constraints.Email
+import javax.validation.constraints.Max
+import javax.validation.constraints.Min
+import javax.validation.constraints.NotNull
+import javax.validation.constraints.Pattern
+import javax.validation.constraints.Size
+import javax.validation.Valid
+
+import kotlin.collections.List
+import kotlin.collections.Map
+
+@Validated
+@RequestMapping("\${api.base-path:/v2}")
+interface StoreApi {
+
+
+ @RequestMapping(
+ method = [RequestMethod.DELETE],
+ value = ["/store/order/{orderId}"]
+ )
+ fun deleteOrder( @PathVariable("orderId") orderId: kotlin.String): ResponseEntity {
+ return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
+ }
+
+
+ @RequestMapping(
+ method = [RequestMethod.GET],
+ value = ["/store/inventory"],
+ produces = ["application/json"]
+ )
+ fun getInventory(): ResponseEntity