Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/samples-kotlin-client.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
- samples/client/petstore/kotlin-explicit
- samples/client/petstore/kotlin-gson
- samples/client/petstore/kotlin-jackson
- samples/client/petstore/kotlin-jackson3
- samples/client/petstore/kotlin-model-prefix-type-mappings
# needs Android configured
#- samples/client/petstore/kotlin-json-request-string
Expand Down Expand Up @@ -74,6 +75,7 @@ jobs:
- samples/client/petstore/kotlin-jvm-spring-3-restclient
- samples/client/echo_api/kotlin-jvm-spring-3-restclient
- samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return
- samples/client/petstore/kotlin-jvm-spring-4-restclient-jackson3
- samples/client/petstore/kotlin-name-parameter-mappings
- samples/client/others/kotlin-jvm-okhttp-parameter-tests
- samples/client/others/kotlin-jvm-okhttp-path-comments
Expand Down
10 changes: 10 additions & 0 deletions bin/configs/kotlin-jackson3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
generatorName: kotlin
outputDir: samples/client/petstore/kotlin-jackson3
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/kotlin-client
additionalProperties:
serializationLibrary: jackson
useJackson3: "true"
artifactId: kotlin-petstore-jackson3
enumPropertyNaming: UPPERCASE
enumUnknownDefaultCase: "true"
10 changes: 10 additions & 0 deletions bin/configs/kotlin-jvm-spring-4-restclient-jackson3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
generatorName: kotlin
outputDir: samples/client/petstore/kotlin-jvm-spring-4-restclient-jackson3
library: jvm-spring-restclient
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/kotlin-client
additionalProperties:
artifactId: kotlin-petstore-spring4-restclient-jackson3
enumUnknownDefaultCase: true
serializationLibrary: jackson
useSpringBoot4: true
5 changes: 3 additions & 2 deletions docs/generators/kotlin.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|idea|Add IntelliJ Idea plugin and mark Kotlin main and test folders as source folders.| |false|
|implicitHeaders|Skip header parameters in the generated API methods.| |false|
|library|Library template (sub-template) to use|<dl><dt>**jvm-ktor**</dt><dd>Platform: Java Virtual Machine. HTTP client: Ktor 1.6.7. JSON processing: Gson, Jackson (default).</dd><dt>**jvm-okhttp4**</dt><dd>[DEFAULT] Platform: Java Virtual Machine. HTTP client: OkHttp 4.2.0 (Android 5.0+ and Java 8+). JSON processing: Moshi 1.8.0.</dd><dt>**jvm-spring-webclient**</dt><dd>Platform: Java Virtual Machine. HTTP: Spring 5 (or 6 with useSpringBoot3 enabled) WebClient. JSON processing: Jackson.</dd><dt>**jvm-spring-restclient**</dt><dd>Platform: Java Virtual Machine. HTTP: Spring 6 RestClient. JSON processing: Jackson.</dd><dt>**jvm-retrofit2**</dt><dd>Platform: Java Virtual Machine. HTTP client: Retrofit 2.6.2.</dd><dt>**multiplatform**</dt><dd>Platform: Kotlin multiplatform. HTTP client: Ktor 1.6.7. JSON processing: Kotlinx Serialization: 1.2.1.</dd><dt>**jvm-volley**</dt><dd>Platform: JVM for Android. HTTP client: Volley 1.2.1. JSON processing: gson 2.8.9 (Deprecated)</dd><dt>**jvm-vertx**</dt><dd>Platform: Java Virtual Machine. HTTP client: Vert.x Web Client. JSON processing: Moshi, Gson or Jackson.</dd></dl>|jvm-okhttp4|
|library|Library template (sub-template) to use|<dl><dt>**jvm-ktor**</dt><dd>Platform: Java Virtual Machine. HTTP client: Ktor 1.6.7. JSON processing: Gson, Jackson (default).</dd><dt>**jvm-okhttp4**</dt><dd>[DEFAULT] Platform: Java Virtual Machine. HTTP client: OkHttp 4.2.0 (Android 5.0+ and Java 8+). JSON processing: Moshi 1.8.0.</dd><dt>**jvm-spring-webclient**</dt><dd>Platform: Java Virtual Machine. HTTP: Spring 5 (or 6 with useSpringBoot3 enabled) WebClient. JSON processing: Jackson.</dd><dt>**jvm-spring-restclient**</dt><dd>Platform: Java Virtual Machine. HTTP: Spring 6 (or 7 with useSpringBoot4 enabled) RestClient. JSON processing: Jackson.</dd><dt>**jvm-retrofit2**</dt><dd>Platform: Java Virtual Machine. HTTP client: Retrofit 2.6.2.</dd><dt>**multiplatform**</dt><dd>Platform: Kotlin multiplatform. HTTP client: Ktor 1.6.7. JSON processing: Kotlinx Serialization: 1.2.1.</dd><dt>**jvm-volley**</dt><dd>Platform: JVM for Android. HTTP client: Volley 1.2.1. JSON processing: gson 2.8.9 (Deprecated)</dd><dt>**jvm-vertx**</dt><dd>Platform: Java Virtual Machine. HTTP client: Vert.x Web Client. JSON processing: Moshi, Gson or Jackson.</dd></dl>|jvm-okhttp4|
|mapFileBinaryToByteArray|Map File and Binary to ByteArray (default: false)| |false|
|modelMutable|Create mutable models| |false|
|moshiCodeGen|Whether to enable codegen with the Moshi library. Refer to the [official Moshi doc](https://github.com/square/moshi#codegen) for more info.| |false|
Expand All @@ -50,12 +50,13 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|sourceFolder|source folder for generated code| |src/main/kotlin|
|supportAndroidApiLevel25AndBelow|[WARNING] This flag will generate code that has a known security vulnerability. It uses `kotlin.io.createTempFile` instead of `java.nio.file.Files.createTempFile` in order to support Android API level 25 and below. For more info, please check the following links https://github.com/OpenAPITools/openapi-generator/security/advisories/GHSA-23x4-m842-fmwf, https://github.com/OpenAPITools/openapi-generator/pull/9284| |false|
|useCoroutines|Whether to use the Coroutines adapter with the retrofit2 library.| |false|
|useJackson3|Use Jackson 3 dependencies (tools.jackson package). Not yet supported for kotlin-client; reserved for future use.| |false|
|useJackson3|Use Jackson 3 dependencies (tools.jackson package). Requires serializationLibrary=jackson. Incompatible with openApiNullable.| |false|
|useNonAsciiHeaders|Allow to use non-ascii headers with the okhttp library| |false|
|useResponseAsReturnType|When using retrofit2 and coroutines, use `Response`&lt;`T`&gt; as return type instead of `T`.| |true|
|useRxJava3|Whether to use the RxJava3 adapter with the retrofit2 library.| |false|
|useSettingsGradle|Whether the project uses settings.gradle.| |false|
|useSpringBoot3|Whether to use the Spring Boot 3 with the jvm-spring-webclient library.| |false|
|useSpringBoot4|Whether to use the Spring Boot 4 with the jvm-spring-restclient library.| |false|

## SUPPORTED VENDOR EXTENSIONS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
public static final String USE_SETTINGS_GRADLE = "useSettingsGradle";
public static final String IDEA = "idea";
public static final String USE_SPRING_BOOT3 = "useSpringBoot3";
public static final String USE_SPRING_BOOT4 = "useSpringBoot4";
public static final String USE_RESPONSE_AS_RETURN_TYPE = "useResponseAsReturnType";

public static final String DATE_LIBRARY = "dateLibrary";
Expand Down Expand Up @@ -252,7 +253,7 @@ public KotlinClientCodegen() {
supportedLibraries.put(JVM_KTOR, "Platform: Java Virtual Machine. HTTP client: Ktor 1.6.7. JSON processing: Gson, Jackson (default).");
supportedLibraries.put(JVM_OKHTTP4, "[DEFAULT] Platform: Java Virtual Machine. HTTP client: OkHttp 4.2.0 (Android 5.0+ and Java 8+). JSON processing: Moshi 1.8.0.");
supportedLibraries.put(JVM_SPRING_WEBCLIENT, "Platform: Java Virtual Machine. HTTP: Spring 5 (or 6 with useSpringBoot3 enabled) WebClient. JSON processing: Jackson.");
supportedLibraries.put(JVM_SPRING_RESTCLIENT, "Platform: Java Virtual Machine. HTTP: Spring 6 RestClient. JSON processing: Jackson.");
supportedLibraries.put(JVM_SPRING_RESTCLIENT, "Platform: Java Virtual Machine. HTTP: Spring 6 (or 7 with useSpringBoot4 enabled) RestClient. JSON processing: Jackson.");
supportedLibraries.put(JVM_RETROFIT2, "Platform: Java Virtual Machine. HTTP client: Retrofit 2.6.2.");
supportedLibraries.put(MULTIPLATFORM, "Platform: Kotlin multiplatform. HTTP client: Ktor 1.6.7. JSON processing: Kotlinx Serialization: 1.2.1.");
supportedLibraries.put(JVM_VOLLEY, "Platform: JVM for Android. HTTP client: Volley 1.2.1. JSON processing: gson 2.8.9 (Deprecated)");
Expand All @@ -275,6 +276,7 @@ public KotlinClientCodegen() {
cliOptions.add(CliOption.newBoolean(USE_RX_JAVA3, "Whether to use the RxJava3 adapter with the retrofit2 library."));
cliOptions.add(CliOption.newBoolean(USE_COROUTINES, "Whether to use the Coroutines adapter with the retrofit2 library."));
cliOptions.add(CliOption.newBoolean(USE_SPRING_BOOT3, "Whether to use the Spring Boot 3 with the jvm-spring-webclient library."));
cliOptions.add(CliOption.newBoolean(USE_SPRING_BOOT4, "Whether to use the Spring Boot 4 with the jvm-spring-restclient library."));
cliOptions.add(CliOption.newBoolean(OMIT_GRADLE_PLUGIN_VERSIONS, "Whether to declare Gradle plugin versions in build files."));
cliOptions.add(CliOption.newBoolean(OMIT_GRADLE_WRAPPER, "Whether to omit Gradle wrapper for creating a sub project."));
cliOptions.add(CliOption.newBoolean(USE_SETTINGS_GRADLE, "Whether the project uses settings.gradle."));
Expand Down Expand Up @@ -303,8 +305,7 @@ public KotlinClientCodegen() {
cliOptions.add(CliOption.newBoolean(USE_NON_ASCII_HEADERS, "Allow to use non-ascii headers with the okhttp library"));
cliOptions.add(CliOption.newBoolean(USE_RESPONSE_AS_RETURN_TYPE, "When using retrofit2 and coroutines, use `Response`<`T`> as return type instead of `T`.", true));

cliOptions.add(CliOption.newBoolean(USE_JACKSON_3,
"Use Jackson 3 dependencies (tools.jackson package). Not yet supported for kotlin-client; reserved for future use."));
cliOptions.add(CliOption.newBoolean(USE_JACKSON_3, "Use Jackson 3 dependencies (tools.jackson package). Requires serializationLibrary=jackson. Incompatible with openApiNullable."));
}

@Override
Expand Down Expand Up @@ -473,9 +474,12 @@ public void processOpts() {
convertPropertyToBooleanAndWriteBack(USE_SPRING_BOOT3);
}

if (isUseJackson3()) {
throw new IllegalArgumentException(
"useJackson3 is not yet supported for kotlin-client. Jackson 3 support for kotlin-client will be added in a future release.");
boolean useSpringBoot4 = additionalProperties.containsKey(USE_SPRING_BOOT4)
&& convertPropertyToBooleanAndWriteBack(USE_SPRING_BOOT4);
if (JVM_SPRING_RESTCLIENT.equals(getLibrary()) && useSpringBoot4 && !isUseJackson3()) {
setUseJackson3(true);
additionalProperties.put(USE_JACKSON_3, true);
applyJackson3Package();
}

if (additionalProperties.containsKey(CodegenConstants.SERIALIZATION_LIBRARY)) {
Expand All @@ -485,6 +489,22 @@ public void processOpts() {
additionalProperties.put(this.serializationLibrary.name(), true);
}

if (isUseJackson3()) {
if (this.serializationLibrary != SERIALIZATION_LIBRARY_TYPE.jackson) {
throw new IllegalArgumentException("useJackson3 requires serializationLibrary=jackson");
}
if (additionalProperties.containsKey("openApiNullable")
&& Boolean.parseBoolean(additionalProperties.get("openApiNullable").toString())) {
throw new IllegalArgumentException("openApiNullable cannot be set with useJackson3");
}
if (!JVM_OKHTTP4.equals(getLibrary()) && !JVM_SPRING_RESTCLIENT.equals(getLibrary())) {
throw new IllegalArgumentException("useJackson3 is only supported for the jvm-okhttp4 and jvm-spring-restclient libraries at this time.");
}
if (JVM_SPRING_RESTCLIENT.equals(getLibrary()) && !useSpringBoot4) {
throw new IllegalArgumentException("useJackson3 with jvm-spring-restclient requires useSpringBoot4=true.");
}
}

if (additionalProperties.containsKey(MAP_FILE_BINARY_TO_BYTE_ARRAY)) {
setMapFileBinaryToByteArray(convertPropertyToBooleanAndWriteBack(MAP_FILE_BINARY_TO_BYTE_ARRAY));
}
Expand Down Expand Up @@ -868,8 +888,9 @@ private void processJvmSpringWebClientLibrary(final String infrastructureFolder)
}

private void processJvmSpringRestClientLibrary(final String infrastructureFolder) {
if (additionalProperties.getOrDefault(USE_SPRING_BOOT3, false).equals(false)) {
throw new RuntimeException("This library must use Spring Boot 3. Try adding '--additional-properties useSpringBoot3=true' to your command.");
if (additionalProperties.getOrDefault(USE_SPRING_BOOT3, false).equals(false)
&& additionalProperties.getOrDefault(USE_SPRING_BOOT4, false).equals(false)) {
throw new RuntimeException("This library requires Spring Boot 3 or 4. Try adding '--additional-properties useSpringBoot3=true' or '--additional-properties useSpringBoot4=true' to your command.");
}

processJvmSpring(infrastructureFolder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,21 @@ buildscript {
ext.vertx_version = "5.1.5"
{{/jvm-vertx}}
{{#jvm-spring}}
{{#useSpringBoot4}}
ext.spring_boot_version = "4.1.0"
{{/useSpringBoot4}}
{{^useSpringBoot4}}
{{#useSpringBoot3}}
ext.spring_boot_version = "3.5.16"
{{/useSpringBoot3}}
{{^useSpringBoot3}}
ext.spring_boot_version = "2.7.18"
{{/useSpringBoot3}}
{{/useSpringBoot4}}
{{/jvm-spring}}
{{#useJackson3}}
ext.jackson3_version = "3.1.5"
{{/useJackson3}}
ext.spotless_version = "7.2.1"

repositories {
Expand Down Expand Up @@ -151,8 +159,13 @@ dependencies {
{{/gson}}
{{#jackson}}
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
{{#useJackson3}}
implementation "tools.jackson.module:jackson-module-kotlin:$jackson3_version"
{{/useJackson3}}
{{^useJackson3}}
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.22.1"
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.1"
{{/useJackson3}}
{{/jackson}}
{{#kotlinx_serialization}}
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.11.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,24 @@ import kotlinx.datetime.LocalTime
import java.util.UUID
{{/gson}}
{{#jackson}}
{{^useJackson3}}
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
{{/useJackson3}}
{{#useJackson3}}
import {{jacksonPackage}}.databind.DeserializationFeature
import {{jacksonPackage}}.databind.json.JsonMapper
import {{jacksonPackage}}.databind.cfg.DateTimeFeature
{{#enumUnknownDefaultCase}}
import {{jacksonPackage}}.databind.cfg.EnumFeature
{{/enumUnknownDefaultCase}}
import com.fasterxml.jackson.annotation.JsonInclude
import {{jacksonPackage}}.module.kotlin.jsonMapper
import {{jacksonPackage}}.module.kotlin.kotlinModule
{{/useJackson3}}
{{/jackson}}
{{#kotlinx_serialization}}
import java.math.BigDecimal
Expand Down Expand Up @@ -120,6 +133,7 @@ import java.util.concurrent.atomic.AtomicLong
}
{{/gson}}
{{#jackson}}
{{^useJackson3}}
@JvmStatic
val jacksonObjectMapper: ObjectMapper = jacksonObjectMapper()
.findAndRegisterModules()
Expand All @@ -129,6 +143,24 @@ import java.util.concurrent.atomic.AtomicLong
{{/enumUnknownDefaultCase}}
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, {{failOnUnknownProperties}})
{{/useJackson3}}
{{#useJackson3}}
@JvmStatic
val jacksonObjectMapper: JsonMapper = jsonMapper {
addModule(kotlinModule())
changeDefaultPropertyInclusion { it.withValueInclusion(JsonInclude.Include.NON_ABSENT) }
{{#enumUnknownDefaultCase}}
enable(EnumFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)
{{/enumUnknownDefaultCase}}
disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS)
{{#failOnUnknownProperties}}
enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
{{/failOnUnknownProperties}}
{{^failOnUnknownProperties}}
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
{{/failOnUnknownProperties}}
}
{{/useJackson3}}
{{/jackson}}
{{#kotlinx_serialization}}
private var isAdaptersInitialized = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import org.threeten.bp.OffsetTime
import com.google.gson.reflect.TypeToken
{{/gson}}
{{#jackson}}
import com.fasterxml.jackson.core.type.TypeReference
import {{jacksonPackage}}.core.type.TypeReference
{{/jackson}}
{{#moshi}}
import com.squareup.moshi.adapter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import org.springframework.web.client.RestClient
import org.springframework.web.client.RestClientResponseException

{{#jackson}}
{{^useJackson3}}
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
{{/useJackson3}}
{{#useJackson3}}
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter
import {{packageName}}.infrastructure.Serializer
{{/useJackson3}}
{{/jackson}}
import org.springframework.http.ResponseEntity
import org.springframework.http.MediaType
Expand All @@ -23,11 +29,20 @@ import {{packageName}}.infrastructure.*
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}open {{/nonPublicApi}}class {{classname}}(client: RestClient) : ApiClient(client) {

{{#jackson}}
{{^useJackson3}}
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}constructor(baseUrl: String) : this(RestClient.builder()
.baseUrl(baseUrl)
.messageConverters { it.add(MappingJackson2HttpMessageConverter()) }
.build()
)
{{/useJackson3}}
{{#useJackson3}}
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}constructor(baseUrl: String) : this(RestClient.builder()
.baseUrl(baseUrl)
.configureMessageConverters { it.registerDefaults().withJsonConverter(JacksonJsonHttpMessageConverter(Serializer.jacksonObjectMapper)) }
.build()
)
{{/useJackson3}}
{{/jackson}}

{{#operation}}
Expand Down
Loading
Loading