diff --git a/.github/workflows/samples-kotlin-client.yaml b/.github/workflows/samples-kotlin-client.yaml
index eee8adcf0649..206cdbc0753e 100644
--- a/.github/workflows/samples-kotlin-client.yaml
+++ b/.github/workflows/samples-kotlin-client.yaml
@@ -6,12 +6,14 @@ on:
- 'samples/client/petstore/kotlin*/**'
- 'samples/client/others/kotlin-jvm-okhttp-parameter-tests/**'
- samples/client/others/kotlin-integer-enum/**
+ - samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/**
pull_request:
paths:
- 'samples/client/petstore/kotlin*/**'
- 'samples/client/others/kotlin-jvm-okhttp-parameter-tests/**'
- samples/client/others/kotlin-integer-enum/**
- samples/client/others/kotlin-oneOf-anyOf-kotlinx-serialization/**
+ - samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/**
jobs:
build:
@@ -66,6 +68,7 @@ jobs:
- samples/client/echo_api/kotlin-jvm-spring-3-webclient
- 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-name-parameter-mappings
- samples/client/others/kotlin-jvm-okhttp-parameter-tests
- samples/client/others/kotlin-jvm-okhttp-path-comments
diff --git a/bin/configs/kotlin-jvm-spring-3-restclient-nullable-return.yaml b/bin/configs/kotlin-jvm-spring-3-restclient-nullable-return.yaml
new file mode 100644
index 000000000000..cae959ae335c
--- /dev/null
+++ b/bin/configs/kotlin-jvm-spring-3-restclient-nullable-return.yaml
@@ -0,0 +1,11 @@
+generatorName: kotlin
+outputDir: samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return
+library: jvm-spring-restclient
+inputSpec: modules/openapi-generator/src/test/resources/3_0/kotlin/nullable-return-type.yaml
+templateDir: modules/openapi-generator/src/main/resources/kotlin-client
+additionalProperties:
+ artifactId: kotlin-jvm-spring-3-restclient-nullable-return
+ enumUnknownDefaultCase: true
+ serializationLibrary: jackson
+ useSpringBoot3: true
+ nullableReturnType: true
diff --git a/bin/utils/test_file_list.yaml b/bin/utils/test_file_list.yaml
index 5e0ea8a9e346..538362b25d36 100644
--- a/bin/utils/test_file_list.yaml
+++ b/bin/utils/test_file_list.yaml
@@ -66,3 +66,5 @@
sha256: 82a6be39c1ed3dada96dfa1833a6709834cb3f9f9d50a19cbd9d49699e46df4f
- filename: "samples/client/petstore/kotlin-jvm-spring-3-restclient/src/test/kotlin/org/openapitools/integration/UserApiTest.kt"
sha256: bc64fb94857a3598e1332f1278307c3078ea9ec4b4aa75690e6eda86e9729a8d
+- filename: "samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/integration/NullableReturnTypeTest.kt"
+ sha256: 41ad4769f4d1bbf616056865deca44ed6dc414ca20d43e38fd9d40a1a81e9c19
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/api_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/api_doc.mustache
index 16eafac78f43..a997cafd1621 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/api_doc.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/api_doc.mustache
@@ -12,7 +12,7 @@ All URIs are relative to *{{basePath}}*
{{#operation}}
# **{{operationId}}**
-> {{#returnType}}{{.}} {{/returnType}}{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
+> {{#returnType}}{{.}}{{#nullableReturnType}}?{{/nullableReturnType}} {{/returnType}}{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
{{summary}}{{#notes}}
@@ -55,7 +55,7 @@ This endpoint does not need any parameter.
### Return type
-{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#generateModelDocs}}[**{{returnType}}**]({{returnBaseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{returnType}}**{{/generateModelDocs}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}}
+{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}{{#nullableReturnType}}?{{/nullableReturnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#generateModelDocs}}[**{{returnType}}{{#nullableReturnType}}?{{/nullableReturnType}}**]({{returnBaseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{returnType}}{{#nullableReturnType}}?{{/nullableReturnType}}**{{/generateModelDocs}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}}
### Authorization
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/api.mustache
index cacb32971237..dc90d004dbdc 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/api.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/api.mustache
@@ -69,7 +69,7 @@ import {{packageName}}.infrastructure.*
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun {{operationId}}({{#allParams}}{{{paramName}}}: {{#isEnum}}{{#isContainer}}kotlin.collections.List<{{enumName}}{{operationIdCamelCase}}>{{/isContainer}}{{^isContainer}}{{enumName}}{{operationIdCamelCase}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}?{{#defaultValue}} = {{>param_default_value}}{{/defaultValue}}{{^defaultValue}} = null{{/defaultValue}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}): {{#returnType}}{{{returnType}}}{{#nullableReturnType}}?{{/nullableReturnType}}{{/returnType}}{{^returnType}}Unit{{/returnType}} {
{{#returnType}}val result = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{{paramName}}} = {{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}
- return result.body!!
+ return result.body{{^nullableReturnType}}!!{{/nullableReturnType}}
{{/returnType}}
}
@@ -79,7 +79,7 @@ import {{packageName}}.infrastructure.*
{{/isDeprecated}}
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun {{operationId}}WithHttpInfo({{#allParams}}{{{paramName}}}: {{#isEnum}}{{#isContainer}}kotlin.collections.List<{{enumName}}{{operationIdCamelCase}}>{{/isContainer}}{{^isContainer}}{{enumName}}{{operationIdCamelCase}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}?{{#defaultValue}} = {{>param_default_value}}{{/defaultValue}}{{^defaultValue}} = null{{/defaultValue}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}): ResponseEntity<{{#returnType}}{{{returnType}}}{{#nullableReturnType}}?{{/nullableReturnType}}{{/returnType}}{{^returnType}}Unit{{/returnType}}> {
val localVariableConfig = {{operationId}}RequestConfig({{#allParams}}{{{paramName}}} = {{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
- return request<{{#hasBodyParam}}{{#bodyParams}}{{{dataType}}}{{/bodyParams}}{{/hasBodyParam}}{{^hasBodyParam}}{{^hasFormParams}}Unit{{/hasFormParams}}{{#hasFormParams}}Map>{{/hasFormParams}}{{/hasBodyParam}}, {{{returnType}}}{{^returnType}}Unit{{/returnType}}>(
+ return request<{{#hasBodyParam}}{{#bodyParams}}{{{dataType}}}{{/bodyParams}}{{/hasBodyParam}}{{^hasBodyParam}}{{^hasFormParams}}Unit{{/hasFormParams}}{{#hasFormParams}}Map>{{/hasFormParams}}{{/hasBodyParam}}, {{#returnType}}{{{returnType}}}{{#nullableReturnType}}?{{/nullableReturnType}}{{/returnType}}{{^returnType}}Unit{{/returnType}}>(
localVariableConfig
)
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/infrastructure/ApiClient.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/infrastructure/ApiClient.kt.mustache
index c6d11989dcef..3612e97011dc 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/infrastructure/ApiClient.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-spring-restclient/infrastructure/ApiClient.kt.mustache
@@ -10,13 +10,13 @@ import org.springframework.util.LinkedMultiValueMap
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}open class ApiClient(protected val client: RestClient) {
- protected inline fun request(requestConfig: RequestConfig): ResponseEntity {
+ protected inline fun request(requestConfig: RequestConfig): ResponseEntity {
return prepare(defaults(requestConfig))
.retrieve()
.toEntity(object : ParameterizedTypeReference() {})
}
- protected fun prepare(requestConfig: RequestConfig) =
+ protected fun prepare(requestConfig: RequestConfig) =
client.method(requestConfig)
.uri(requestConfig)
.headers(requestConfig)
@@ -45,7 +45,7 @@ import org.springframework.util.LinkedMultiValueMap
private fun RestClient.RequestBodySpec.headers(requestConfig: RequestConfig) =
apply { requestConfig.headers.forEach { (name, value) -> header(name, value) } }
- private fun RestClient.RequestBodySpec.nullableBody(requestConfig: RequestConfig): RestClient.RequestBodySpec {
+ private fun RestClient.RequestBodySpec.nullableBody(requestConfig: RequestConfig): RestClient.RequestBodySpec {
when {
requestConfig.headers[HttpHeaders.CONTENT_TYPE] == MediaType.MULTIPART_FORM_DATA_VALUE -> {
val parts = LinkedMultiValueMap()
@@ -59,7 +59,7 @@ import org.springframework.util.LinkedMultiValueMap
}
else -> {
- return apply { if (requestConfig.body != null) body(requestConfig.body) }
+ return apply { if (requestConfig.body != null) body(requestConfig.body as Any) }
}
}
}
diff --git a/modules/openapi-generator/src/test/resources/3_0/kotlin/nullable-return-type.yaml b/modules/openapi-generator/src/test/resources/3_0/kotlin/nullable-return-type.yaml
new file mode 100644
index 000000000000..c8c945875c9e
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/kotlin/nullable-return-type.yaml
@@ -0,0 +1,34 @@
+openapi: 3.0.3
+info:
+ title: Nullable Return Type Test
+ version: 1.0.0
+paths:
+ /nullable-string:
+ post:
+ operationId: returnNullableString
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PingRequest'
+ responses:
+ "200":
+ description: Successful response, body may be empty
+ content:
+ text/html:
+ schema:
+ type: string
+ /always-empty:
+ get:
+ operationId: returnNothing
+ responses:
+ "204":
+ description: No content
+components:
+ schemas:
+ PingRequest:
+ type: object
+ properties:
+ msg:
+ type: string
diff --git a/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
index d13aa82aab69..0f8f3a7052d0 100644
--- a/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
+++ b/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
@@ -10,13 +10,13 @@ import org.springframework.util.LinkedMultiValueMap
open class ApiClient(protected val client: RestClient) {
- protected inline fun request(requestConfig: RequestConfig): ResponseEntity {
+ protected inline fun request(requestConfig: RequestConfig): ResponseEntity {
return prepare(defaults(requestConfig))
.retrieve()
.toEntity(object : ParameterizedTypeReference() {})
}
- protected fun prepare(requestConfig: RequestConfig) =
+ protected fun prepare(requestConfig: RequestConfig) =
client.method(requestConfig)
.uri(requestConfig)
.headers(requestConfig)
@@ -45,7 +45,7 @@ open class ApiClient(protected val client: RestClient) {
private fun RestClient.RequestBodySpec.headers(requestConfig: RequestConfig) =
apply { requestConfig.headers.forEach { (name, value) -> header(name, value) } }
- private fun RestClient.RequestBodySpec.nullableBody(requestConfig: RequestConfig): RestClient.RequestBodySpec {
+ private fun RestClient.RequestBodySpec.nullableBody(requestConfig: RequestConfig): RestClient.RequestBodySpec {
when {
requestConfig.headers[HttpHeaders.CONTENT_TYPE] == MediaType.MULTIPART_FORM_DATA_VALUE -> {
val parts = LinkedMultiValueMap()
@@ -59,7 +59,7 @@ open class ApiClient(protected val client: RestClient) {
}
else -> {
- return apply { if (requestConfig.body != null) body(requestConfig.body) }
+ return apply { if (requestConfig.body != null) body(requestConfig.body as Any) }
}
}
}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator-ignore b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator-ignore
new file mode 100644
index 000000000000..7484ee590a38
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.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/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator/FILES b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator/FILES
new file mode 100644
index 000000000000..607a9923eefa
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator/FILES
@@ -0,0 +1,17 @@
+README.md
+build.gradle
+docs/DefaultApi.md
+docs/PingRequest.md
+gradle/wrapper/gradle-wrapper.jar
+gradle/wrapper/gradle-wrapper.properties
+gradlew
+gradlew.bat
+settings.gradle
+src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt
+src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
+src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
+src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
+src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
+src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
+src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
+src/main/kotlin/org/openapitools/client/models/PingRequest.kt
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator/VERSION b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator/VERSION
new file mode 100644
index 000000000000..f7962df3e243
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/.openapi-generator/VERSION
@@ -0,0 +1 @@
+7.22.0-SNAPSHOT
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/README.md b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/README.md
new file mode 100644
index 000000000000..73fa6ae4e899
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/README.md
@@ -0,0 +1,62 @@
+# org.openapitools.client - Kotlin client library for Nullable Return Type Test
+
+No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+
+## Overview
+This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate an API client.
+
+- API version: 1.0.0
+- Package version:
+- Generator version: 7.22.0-SNAPSHOT
+- Build package: org.openapitools.codegen.languages.KotlinClientCodegen
+
+## Requires
+
+* Kotlin 2.2.20
+* Gradle 8.14
+
+## Build
+
+First, create the gradle wrapper script:
+
+```
+gradle wrapper
+```
+
+Then, run:
+
+```
+./gradlew check assemble
+```
+
+This runs all tests and packages the library.
+
+## Features/Implementation Notes
+
+* Supports JSON inputs/outputs, File inputs, and Form inputs.
+* Supports collection formats for query parameters: csv, tsv, ssv, pipes.
+* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions.
+* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets.
+
+
+## Documentation for API Endpoints
+
+All URIs are relative to *http://localhost*
+
+| Class | Method | HTTP request | Description |
+| ------------ | ------------- | ------------- | ------------- |
+| *DefaultApi* | [**returnNothing**](docs/DefaultApi.md#returnnothing) | **GET** /always-empty | |
+| *DefaultApi* | [**returnNullableString**](docs/DefaultApi.md#returnnullablestring) | **POST** /nullable-string | |
+
+
+
+## Documentation for Models
+
+ - [org.openapitools.client.models.PingRequest](docs/PingRequest.md)
+
+
+
+## Documentation for Authorization
+
+Endpoints do not require authorization.
+
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/build.gradle b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/build.gradle
new file mode 100644
index 000000000000..0fd5a69bda53
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/build.gradle
@@ -0,0 +1,85 @@
+group 'org.openapitools'
+version '1.0.0'
+
+wrapper {
+ gradleVersion = '8.14.3'
+ distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
+}
+
+buildscript {
+ ext.kotlin_version = '2.2.20'
+ ext.spring_boot_version = "3.5.5"
+ ext.spotless_version = "7.2.1"
+
+ repositories {
+ maven { url "https://repo1.maven.org/maven2" }
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.diffplug.spotless:spotless-plugin-gradle:$spotless_version"
+ }
+}
+
+apply plugin: 'kotlin'
+apply plugin: 'maven-publish'
+apply plugin: 'com.diffplug.spotless'
+
+repositories {
+ maven { url "https://repo1.maven.org/maven2" }
+}
+
+// Use spotless plugin to automatically format code, remove unused import, etc
+// To apply changes directly to the file, run `gradlew spotlessApply`
+// Ref: https://github.com/diffplug/spotless/tree/main/plugin-gradle
+spotless {
+ // comment out below to run spotless as part of the `check` task
+ enforceCheck false
+
+ format 'misc', {
+ // define the files (e.g. '*.gradle', '*.md') to apply `misc` to
+ target '.gitignore'
+
+ // define the steps to apply to those files
+ trimTrailingWhitespace()
+ indentWithSpaces() // Takes an integer argument if you don't like 4
+ endWithNewline()
+ }
+ kotlin {
+ ktfmt()
+ }
+}
+
+test {
+ useJUnitPlatform()
+}
+
+kotlin {
+ jvmToolchain {
+ languageVersion.set(JavaLanguageVersion.of(17))
+ }
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
+ implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.20.0"
+ implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.20.0"
+ implementation "org.springframework.boot:spring-boot-starter-web:$spring_boot_version"
+ testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
+ testImplementation "org.springframework.boot:spring-boot-test:$spring_boot_version"
+}
+
+java {
+ withSourcesJar()
+}
+
+publishing {
+ publications {
+ maven(MavenPublication) {
+ groupId = 'org.openapitools'
+ artifactId = 'kotlin-jvm-spring-3-restclient-nullable-return'
+ version = '1.0.0'
+ from components.java
+ }
+ }
+}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/docs/DefaultApi.md b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/docs/DefaultApi.md
new file mode 100644
index 000000000000..84a6d6f0b427
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/docs/DefaultApi.md
@@ -0,0 +1,94 @@
+# DefaultApi
+
+All URIs are relative to *http://localhost*
+
+| Method | HTTP request | Description |
+| ------------- | ------------- | ------------- |
+| [**returnNothing**](DefaultApi.md#returnNothing) | **GET** /always-empty | |
+| [**returnNullableString**](DefaultApi.md#returnNullableString) | **POST** /nullable-string | |
+
+
+
+# **returnNothing**
+> returnNothing()
+
+
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = DefaultApi()
+try {
+ apiInstance.returnNothing()
+} catch (e: ClientException) {
+ println("4xx response calling DefaultApi#returnNothing")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling DefaultApi#returnNothing")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+This endpoint does not need any parameter.
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **returnNullableString**
+> kotlin.String? returnNullableString(pingRequest)
+
+
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = DefaultApi()
+val pingRequest : PingRequest = // PingRequest |
+try {
+ val result : kotlin.String? = apiInstance.returnNullableString(pingRequest)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling DefaultApi#returnNullableString")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling DefaultApi#returnNullableString")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+| Name | Type | Description | Notes |
+| ------------- | ------------- | ------------- | ------------- |
+| **pingRequest** | [**PingRequest**](PingRequest.md)| | |
+
+### Return type
+
+**kotlin.String?**
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: application/json
+ - **Accept**: text/html
+
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/docs/PingRequest.md b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/docs/PingRequest.md
new file mode 100644
index 000000000000..006661ce8d26
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/docs/PingRequest.md
@@ -0,0 +1,10 @@
+
+# PingRequest
+
+## Properties
+| Name | Type | Description | Notes |
+| ------------ | ------------- | ------------- | ------------- |
+| **msg** | **kotlin.String** | | [optional] |
+
+
+
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradle/wrapper/gradle-wrapper.jar b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000000..2c3521197d7c
Binary files /dev/null and b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradle/wrapper/gradle-wrapper.properties b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000000..7705927e949f
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradlew b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradlew
new file mode 100755
index 000000000000..51eb8bb47109
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradlew
@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+[ -h "$app_path" ]
+do
+ls=$( ls -ld "$app_path" )
+link=${ls#*' -> '}
+case $link in #(
+/*) app_path=$link ;; #(
+*) app_path=$APP_HOME$link ;;
+esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+echo "$*"
+} >&2
+
+die () {
+echo
+echo "$*"
+echo
+exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+CYGWIN* ) cygwin=true ;; #(
+Darwin* ) darwin=true ;; #(
+MSYS* | MINGW* ) msys=true ;; #(
+NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+# IBM's JDK on AIX uses strange locations for the executables
+JAVACMD=$JAVA_HOME/jre/sh/java
+else
+JAVACMD=$JAVA_HOME/bin/java
+fi
+if [ ! -x "$JAVACMD" ] ; then
+die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+else
+JAVACMD=java
+if ! command -v java >/dev/null 2>&1
+then
+die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+case $MAX_FD in #(
+max*)
+# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+# shellcheck disable=SC2039,SC3045
+MAX_FD=$( ulimit -H -n ) ||
+warn "Could not query maximum file descriptor limit"
+esac
+case $MAX_FD in #(
+'' | soft) :;; #(
+*)
+# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+# shellcheck disable=SC2039,SC3045
+ulimit -n "$MAX_FD" ||
+warn "Could not set maximum file descriptor limit to $MAX_FD"
+esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+# Now convert the arguments - kludge to limit ourselves to /bin/sh
+for arg do
+if
+case $arg in #(
+-*) false ;; # don't mess with options #(
+/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+[ -e "$t" ] ;; #(
+*) false ;;
+esac
+then
+arg=$( cygpath --path --ignore --mixed "$arg" )
+fi
+# Roll the args list around exactly as many times as the number of
+# args, so each arg winds up back in the position where it started, but
+# possibly modified.
+#
+# NB: a `for` loop captures its iteration list before it begins, so
+# changing the positional parameters here affects neither the number of
+# iterations, nor the values presented in `arg`.
+shift # remove old arg
+set -- "$@" "$arg" # push replacement arg
+done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+"-Dorg.gradle.appname=$APP_BASE_NAME" \
+-classpath "$CLASSPATH" \
+org.gradle.wrapper.GradleWrapperMain \
+"$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+xargs -n1 |
+sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+tr '\n' ' '
+)" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradlew.bat b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradlew.bat
new file mode 100644
index 000000000000..9d21a21834d5
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/settings.gradle b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/settings.gradle
new file mode 100644
index 000000000000..130b0a65de68
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'kotlin-jvm-spring-3-restclient-nullable-return'
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt
new file mode 100644
index 000000000000..4b59d01cba91
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt
@@ -0,0 +1,116 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.apis
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+import org.springframework.web.client.RestClient
+import org.springframework.web.client.RestClientResponseException
+
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
+import org.springframework.http.ResponseEntity
+import org.springframework.http.MediaType
+
+
+import org.openapitools.client.models.PingRequest
+import org.openapitools.client.infrastructure.*
+
+open class DefaultApi(client: RestClient) : ApiClient(client) {
+
+ constructor(baseUrl: String) : this(RestClient.builder()
+ .baseUrl(baseUrl)
+ .messageConverters { it.add(MappingJackson2HttpMessageConverter()) }
+ .build()
+ )
+
+
+ @Throws(RestClientResponseException::class)
+ fun returnNothing(): Unit {
+ returnNothingWithHttpInfo()
+ }
+
+ @Throws(RestClientResponseException::class)
+ fun returnNothingWithHttpInfo(): ResponseEntity {
+ val localVariableConfig = returnNothingRequestConfig()
+ return request(
+ localVariableConfig
+ )
+ }
+
+ fun returnNothingRequestConfig() : RequestConfig {
+ val localVariableBody = null
+ val localVariableQuery = mutableMapOf>()
+ val localVariableHeaders: MutableMap = mutableMapOf()
+
+ val params = mutableMapOf(
+ )
+
+ return RequestConfig(
+ method = RequestMethod.GET,
+ path = "/always-empty",
+ params = params,
+ query = localVariableQuery,
+ headers = localVariableHeaders,
+ requiresAuthentication = false,
+ body = localVariableBody
+ )
+ }
+
+
+ @Throws(RestClientResponseException::class)
+ fun returnNullableString(pingRequest: PingRequest): kotlin.String? {
+ val result = returnNullableStringWithHttpInfo(pingRequest = pingRequest)
+ return result.body
+ }
+
+ @Throws(RestClientResponseException::class)
+ fun returnNullableStringWithHttpInfo(pingRequest: PingRequest): ResponseEntity {
+ val localVariableConfig = returnNullableStringRequestConfig(pingRequest = pingRequest)
+ return request(
+ localVariableConfig
+ )
+ }
+
+ fun returnNullableStringRequestConfig(pingRequest: PingRequest) : RequestConfig {
+ val localVariableBody = pingRequest
+ val localVariableQuery = mutableMapOf>()
+ val localVariableHeaders: MutableMap = mutableMapOf()
+ localVariableHeaders["Content-Type"] = "application/json"
+ localVariableHeaders["Accept"] = "text/html"
+
+ val params = mutableMapOf(
+ )
+
+ return RequestConfig(
+ method = RequestMethod.POST,
+ path = "/nullable-string",
+ params = params,
+ query = localVariableQuery,
+ headers = localVariableHeaders,
+ requiresAuthentication = false,
+ body = localVariableBody
+ )
+ }
+
+}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
new file mode 100644
index 000000000000..7fe8da468374
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
@@ -0,0 +1,23 @@
+package org.openapitools.client.infrastructure
+
+typealias MultiValueMap = MutableMap>
+
+fun collectionDelimiter(collectionFormat: String): String = when(collectionFormat) {
+ "csv" -> ","
+ "tsv" -> "\t"
+ "pipe" -> "|"
+ "space" -> " "
+ else -> ""
+}
+
+val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" }
+
+fun toMultiValue(items: Array, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List
+ = toMultiValue(items.asIterable(), collectionFormat, map)
+
+fun toMultiValue(items: Iterable, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List {
+ return when(collectionFormat) {
+ "multi" -> items.map(map)
+ else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map))
+ }
+}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
new file mode 100644
index 000000000000..0f8f3a7052d0
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
@@ -0,0 +1,76 @@
+package org.openapitools.client.infrastructure;
+
+import org.springframework.core.ParameterizedTypeReference
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpMethod
+import org.springframework.http.MediaType
+import org.springframework.web.client.RestClient
+import org.springframework.http.ResponseEntity
+import org.springframework.util.LinkedMultiValueMap
+
+open class ApiClient(protected val client: RestClient) {
+
+ protected inline fun request(requestConfig: RequestConfig): ResponseEntity {
+ return prepare(defaults(requestConfig))
+ .retrieve()
+ .toEntity(object : ParameterizedTypeReference() {})
+ }
+
+ protected fun prepare(requestConfig: RequestConfig) =
+ client.method(requestConfig)
+ .uri(requestConfig)
+ .headers(requestConfig)
+ .nullableBody(requestConfig)
+
+ protected fun defaults(requestConfig: RequestConfig) =
+ requestConfig.apply {
+ if (body != null && headers[HttpHeaders.CONTENT_TYPE].isNullOrEmpty()) {
+ headers[HttpHeaders.CONTENT_TYPE] = MediaType.APPLICATION_JSON_VALUE
+ }
+ if (headers[HttpHeaders.ACCEPT].isNullOrEmpty()) {
+ headers[HttpHeaders.ACCEPT] = MediaType.APPLICATION_JSON_VALUE
+ }
+ }
+
+ private fun RestClient.method(requestConfig: RequestConfig)=
+ method(HttpMethod.valueOf(requestConfig.method.name))
+
+ private fun RestClient.RequestBodyUriSpec.uri(requestConfig: RequestConfig) =
+ uri(requestConfig.path) { builder ->
+ builder
+ .queryParams(LinkedMultiValueMap(requestConfig.query))
+ .build(requestConfig.params)
+ }
+
+ private fun RestClient.RequestBodySpec.headers(requestConfig: RequestConfig) =
+ apply { requestConfig.headers.forEach { (name, value) -> header(name, value) } }
+
+ private fun RestClient.RequestBodySpec.nullableBody(requestConfig: RequestConfig): RestClient.RequestBodySpec {
+ when {
+ requestConfig.headers[HttpHeaders.CONTENT_TYPE] == MediaType.MULTIPART_FORM_DATA_VALUE -> {
+ val parts = LinkedMultiValueMap()
+ @Suppress("UNCHECKED_CAST")
+ (requestConfig.body as Map>).forEach { (name, part) ->
+ if (part.body != null) {
+ parts.add(name, part.body)
+ }
+ }
+ return apply { body(parts) }
+ }
+
+ else -> {
+ return apply { if (requestConfig.body != null) body(requestConfig.body as Any) }
+ }
+ }
+ }
+}
+
+inline fun parseDateToQueryString(value : T): String {
+ /*
+ .replace("\"", "") converts the json object string to an actual string for the query parameter.
+ The moshi or gson adapter allows a more generic solution instead of trying to use a native
+ formatter. It also easily allows to provide a simple way to define a custom date format pattern
+ inside a gson/moshi adapter.
+ */
+ return Serializer.jacksonObjectMapper.writeValueAsString(value).replace("\"", "")
+ }
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
new file mode 100644
index 000000000000..c2a5c99ec7e6
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.infrastructure
+
+/**
+ * Defines a config object for a given part of a multi-part request.
+ * NOTE: Headers is a Map because rfc2616 defines
+ * multi-valued headers as csv-only.
+ *
+ * @property headers The headers for this part
+ * @property body The body content for this part
+ * @property serializer Optional custom serializer for JSON content. When provided, this will be
+ * used instead of the default serialization for parts with application/json
+ * content-type. This allows capturing type information at the call site to
+ * avoid issues with type erasure in kotlinx.serialization.
+ */
+data class PartConfig(
+ val headers: MutableMap = mutableMapOf(),
+ val body: T? = null,
+ val serializer: ((Any?) -> String)? = null
+)
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
new file mode 100644
index 000000000000..6578b9381b78
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.infrastructure
+
+/**
+ * Defines a config object for a given request.
+ * NOTE: This object doesn't include 'body' because it
+ * allows for caching of the constructed object
+ * for many request definitions.
+ * NOTE: Headers is a Map because rfc2616 defines
+ * multi-valued headers as csv-only.
+ */
+data class RequestConfig(
+ val method: RequestMethod,
+ val path: String,
+ val headers: MutableMap = mutableMapOf(),
+ val params: MutableMap = mutableMapOf(),
+ val query: MutableMap> = mutableMapOf(),
+ val requiresAuthentication: Boolean,
+ val body: T? = null
+)
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
new file mode 100644
index 000000000000..beb56f07cdde
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
@@ -0,0 +1,8 @@
+package org.openapitools.client.infrastructure
+
+/**
+ * Provides enumerated HTTP verbs
+ */
+enum class RequestMethod {
+ GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT
+}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
new file mode 100644
index 000000000000..80783430664b
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
@@ -0,0 +1,17 @@
+package org.openapitools.client.infrastructure
+
+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
+
+object Serializer {
+ @JvmStatic
+ val jacksonObjectMapper: ObjectMapper = jacksonObjectMapper()
+ .findAndRegisterModules()
+ .setSerializationInclusion(JsonInclude.Include.NON_ABSENT)
+ .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true)
+ .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/models/PingRequest.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/models/PingRequest.kt
new file mode 100644
index 000000000000..17fa6610a1c9
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/main/kotlin/org/openapitools/client/models/PingRequest.kt
@@ -0,0 +1,46 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.models
+
+
+import com.fasterxml.jackson.annotation.JsonEnumDefaultValue
+import com.fasterxml.jackson.annotation.JsonProperty
+
+/**
+ *
+ *
+ * @param msg
+ */
+
+
+data class PingRequest (
+
+ @get:JsonProperty("msg")
+ val msg: kotlin.String? = null
+
+) {
+
+
+}
+
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt
new file mode 100644
index 000000000000..4ebab2a9ddd4
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt
@@ -0,0 +1,52 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.apis
+
+import io.kotlintest.shouldBe
+import io.kotlintest.specs.ShouldSpec
+
+import org.openapitools.client.apis.DefaultApi
+import org.openapitools.client.models.PingRequest
+
+class DefaultApiTest : ShouldSpec() {
+ init {
+ // uncomment below to create an instance of DefaultApi
+ //val apiInstance = DefaultApi()
+
+ // to test returnNothing
+ should("test returnNothing") {
+ // uncomment below to test returnNothing
+ //apiInstance.returnNothing()
+ }
+
+ // to test returnNullableString
+ should("test returnNullableString") {
+ // uncomment below to test returnNullableString
+ //val pingRequest : PingRequest = // PingRequest |
+ //val result : kotlin.String? = apiInstance.returnNullableString(pingRequest)
+ //result shouldBe ("TODO")
+ }
+
+ }
+}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/client/models/PingRequestTest.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/client/models/PingRequestTest.kt
new file mode 100644
index 000000000000..2bf7e6b43fdf
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/client/models/PingRequestTest.kt
@@ -0,0 +1,43 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.models
+
+import io.kotlintest.shouldBe
+import io.kotlintest.specs.ShouldSpec
+
+import org.openapitools.client.models.PingRequest
+
+class PingRequestTest : ShouldSpec() {
+ init {
+ // uncomment below to create an instance of PingRequest
+ //val modelInstance = PingRequest()
+
+ // to test the property `msg`
+ should("test msg") {
+ // uncomment below to test the property
+ //modelInstance.msg shouldBe ("TODO")
+ }
+
+ }
+}
diff --git a/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/integration/NullableReturnTypeTest.kt b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/integration/NullableReturnTypeTest.kt
new file mode 100644
index 000000000000..3d8c712092d5
--- /dev/null
+++ b/samples/client/others/kotlin-jvm-spring-3-restclient-nullable-return/src/test/kotlin/org/openapitools/integration/NullableReturnTypeTest.kt
@@ -0,0 +1,55 @@
+package org.openapitools.integration
+
+import io.kotlintest.shouldBe
+import io.kotlintest.specs.ShouldSpec
+import org.openapitools.client.apis.DefaultApi
+import org.openapitools.client.models.PingRequest
+import org.springframework.boot.test.web.client.MockServerRestClientCustomizer
+import org.springframework.http.HttpMethod
+import org.springframework.http.MediaType.TEXT_HTML
+import org.springframework.test.web.client.match.MockRestRequestMatchers.method
+import org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
+import org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess
+import org.springframework.web.client.RestClient
+
+class NullableReturnTypeTest : ShouldSpec() {
+ init {
+ should("return null when the response body is empty and the return type is nullable") {
+ val restClientBuilder: RestClient.Builder = RestClient.builder()
+ val mockServer = MockServerRestClientCustomizer().let {
+ it.customize(restClientBuilder)
+ it.getServer(restClientBuilder)
+ }
+ val api = DefaultApi(restClientBuilder.build())
+
+ mockServer.expect(requestTo("/nullable-string"))
+ .andExpect(method(HttpMethod.POST))
+ .andRespond(withSuccess("", TEXT_HTML))
+
+ val response = api.returnNullableString(PingRequest(msg = "hello"))
+
+ mockServer.verify()
+
+ response shouldBe null
+ }
+
+ should("return the body when the response has one and the return type is nullable") {
+ val restClientBuilder: RestClient.Builder = RestClient.builder()
+ val mockServer = MockServerRestClientCustomizer().let {
+ it.customize(restClientBuilder)
+ it.getServer(restClientBuilder)
+ }
+ val api = DefaultApi(restClientBuilder.build())
+
+ mockServer.expect(requestTo("/nullable-string"))
+ .andExpect(method(HttpMethod.POST))
+ .andRespond(withSuccess("ok", TEXT_HTML))
+
+ val response = api.returnNullableString(PingRequest(msg = "hello"))
+
+ mockServer.verify()
+
+ response shouldBe "ok"
+ }
+ }
+}
diff --git a/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
index d13aa82aab69..0f8f3a7052d0 100644
--- a/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
+++ b/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
@@ -10,13 +10,13 @@ import org.springframework.util.LinkedMultiValueMap
open class ApiClient(protected val client: RestClient) {
- protected inline fun request(requestConfig: RequestConfig): ResponseEntity {
+ protected inline fun request(requestConfig: RequestConfig): ResponseEntity {
return prepare(defaults(requestConfig))
.retrieve()
.toEntity(object : ParameterizedTypeReference() {})
}
- protected fun prepare(requestConfig: RequestConfig) =
+ protected fun prepare(requestConfig: RequestConfig) =
client.method(requestConfig)
.uri(requestConfig)
.headers(requestConfig)
@@ -45,7 +45,7 @@ open class ApiClient(protected val client: RestClient) {
private fun RestClient.RequestBodySpec.headers(requestConfig: RequestConfig) =
apply { requestConfig.headers.forEach { (name, value) -> header(name, value) } }
- private fun RestClient.RequestBodySpec.nullableBody(requestConfig: RequestConfig): RestClient.RequestBodySpec {
+ private fun RestClient.RequestBodySpec.nullableBody(requestConfig: RequestConfig): RestClient.RequestBodySpec {
when {
requestConfig.headers[HttpHeaders.CONTENT_TYPE] == MediaType.MULTIPART_FORM_DATA_VALUE -> {
val parts = LinkedMultiValueMap()
@@ -59,7 +59,7 @@ open class ApiClient(protected val client: RestClient) {
}
else -> {
- return apply { if (requestConfig.body != null) body(requestConfig.body) }
+ return apply { if (requestConfig.body != null) body(requestConfig.body as Any) }
}
}
}
diff --git a/samples/client/petstore/kotlin-nullable/docs/PetApi.md b/samples/client/petstore/kotlin-nullable/docs/PetApi.md
index 02061114df28..c34fce5f4a46 100644
--- a/samples/client/petstore/kotlin-nullable/docs/PetApi.md
+++ b/samples/client/petstore/kotlin-nullable/docs/PetApi.md
@@ -108,7 +108,7 @@ Configure petstore_auth:
# **findPetsByStatus**
-> kotlin.collections.List<Pet> findPetsByStatus(status)
+> kotlin.collections.List<Pet>? findPetsByStatus(status)
Finds Pets by status
@@ -141,7 +141,7 @@ try {
### Return type
-[**kotlin.collections.List<Pet>**](Pet.md)
+[**kotlin.collections.List<Pet>?**](Pet.md)
### Authorization
@@ -156,7 +156,7 @@ Configure petstore_auth:
# **findPetsByTags**
-> kotlin.collections.List<Pet> findPetsByTags(tags)
+> kotlin.collections.List<Pet>? findPetsByTags(tags)
Finds Pets by tags
@@ -189,7 +189,7 @@ try {
### Return type
-[**kotlin.collections.List<Pet>**](Pet.md)
+[**kotlin.collections.List<Pet>?**](Pet.md)
### Authorization
@@ -204,7 +204,7 @@ Configure petstore_auth:
# **getPetById**
-> Pet getPetById(petId)
+> Pet? getPetById(petId)
Find pet by ID
@@ -237,7 +237,7 @@ try {
### Return type
-[**Pet**](Pet.md)
+[**Pet?**](Pet.md)
### Authorization
@@ -347,7 +347,7 @@ Configure petstore_auth:
# **uploadFile**
-> ModelApiResponse uploadFile(petId, additionalMetadata, file)
+> ModelApiResponse? uploadFile(petId, additionalMetadata, file)
uploads an image
@@ -382,7 +382,7 @@ try {
### Return type
-[**ModelApiResponse**](ModelApiResponse.md)
+[**ModelApiResponse?**](ModelApiResponse.md)
### Authorization
diff --git a/samples/client/petstore/kotlin-nullable/docs/StoreApi.md b/samples/client/petstore/kotlin-nullable/docs/StoreApi.md
index 3643359fd101..7a65eab968d3 100644
--- a/samples/client/petstore/kotlin-nullable/docs/StoreApi.md
+++ b/samples/client/petstore/kotlin-nullable/docs/StoreApi.md
@@ -57,7 +57,7 @@ No authorization required
# **getInventory**
-> kotlin.collections.Map<kotlin.String, kotlin.Int> getInventory()
+> kotlin.collections.Map<kotlin.String, kotlin.Int>? getInventory()
Returns pet inventories by status
@@ -87,7 +87,7 @@ This endpoint does not need any parameter.
### Return type
-**kotlin.collections.Map<kotlin.String, kotlin.Int>**
+**kotlin.collections.Map<kotlin.String, kotlin.Int>?**
### Authorization
@@ -103,7 +103,7 @@ Configure api_key:
# **getOrderById**
-> Order getOrderById(orderId)
+> Order? getOrderById(orderId)
Find purchase order by ID
@@ -136,7 +136,7 @@ try {
### Return type
-[**Order**](Order.md)
+[**Order?**](Order.md)
### Authorization
@@ -149,7 +149,7 @@ No authorization required
# **placeOrder**
-> Order placeOrder(body)
+> Order? placeOrder(body)
Place an order for a pet
@@ -180,7 +180,7 @@ try {
### Return type
-[**Order**](Order.md)
+[**Order?**](Order.md)
### Authorization
diff --git a/samples/client/petstore/kotlin-nullable/docs/UserApi.md b/samples/client/petstore/kotlin-nullable/docs/UserApi.md
index 358b8a32ab0c..9f71f2df6933 100644
--- a/samples/client/petstore/kotlin-nullable/docs/UserApi.md
+++ b/samples/client/petstore/kotlin-nullable/docs/UserApi.md
@@ -192,7 +192,7 @@ No authorization required
# **getUserByName**
-> User getUserByName(username)
+> User? getUserByName(username)
Get user by user name
@@ -223,7 +223,7 @@ try {
### Return type
-[**User**](User.md)
+[**User?**](User.md)
### Authorization
@@ -236,7 +236,7 @@ No authorization required
# **loginUser**
-> kotlin.String loginUser(username, password)
+> kotlin.String? loginUser(username, password)
Logs user into the system
@@ -269,7 +269,7 @@ try {
### Return type
-**kotlin.String**
+**kotlin.String?**
### Authorization