diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache index ef2426d83371..5716f8656c32 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache @@ -3,15 +3,15 @@ version '{{artifactVersion}}' {{^omitGradleWrapper}} wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } {{/omitGradleWrapper}} buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' {{#jvm-ktor}} - ext.ktor_version = '1.6.7' + ext.ktor_version = '2.0.3' {{/jvm-ktor}} {{#jvm-retrofit2}} ext.retrofitVersion = '2.9.0' @@ -72,46 +72,49 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" {{^doNotUseRxAndCoroutines}} {{#useCoroutines}} - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3" {{/useCoroutines}} {{/doNotUseRxAndCoroutines}} {{#moshi}} {{^moshiCodeGen}} implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" {{/moshiCodeGen}} {{#moshiCodeGen}} - implementation "com.squareup.moshi:moshi:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - kapt "com.squareup.moshi:moshi-kotlin-codegen:1.12.0" + implementation "com.squareup.moshi:moshi:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0" {{/moshiCodeGen}} {{/moshi}} {{#gson}} - implementation "com.google.code.gson:gson:2.8.7" + implementation "com.google.code.gson:gson:2.9.0" {{/gson}} {{#jackson}} implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3" - implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3" + implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3" {{/jackson}} {{#kotlinx_serialization}} - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3" {{/kotlinx_serialization}} {{#jvm-ktor}} implementation "io.ktor:ktor-client-core:$ktor_version" + implementation "io.ktor:ktor-client-content-negotiation:$ktor_version" {{#gson}} + implementation "io.ktor:ktor-serialization-gson:$ktor_version" implementation "io.ktor:ktor-client-gson:$ktor_version" {{/gson}} {{#jackson}} implementation "io.ktor:ktor-client-jackson:$ktor_version" + implementation "io.ktor:ktor-serialization-jackson:$ktor_version" {{/jackson}} {{/jvm-ktor}} {{#jvm-okhttp3}} implementation "com.squareup.okhttp3:okhttp:3.12.13" {{/jvm-okhttp3}} {{#jvm-okhttp4}} - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.okhttp3:okhttp:4.10.0" {{/jvm-okhttp4}} {{#threetenbp}} implementation "org.threeten:threetenbp:1.5.1" @@ -120,7 +123,7 @@ dependencies { {{#hasOAuthMethods}} implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2" {{/hasOAuthMethods}} - implementation "com.squareup.okhttp3:logging-interceptor:4.9.1" + implementation "com.squareup.okhttp3:logging-interceptor:4.10.0" {{#useRxJava}} implementation "io.reactivex:rxjava:$rxJavaVersion" implementation "com.squareup.retrofit2:adapter-rxjava:$retrofitVersion" diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/api.mustache index 5b6c968d38b2..168401c67435 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/api.mustache @@ -9,9 +9,10 @@ import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine import io.ktor.http.ParametersBuilder - {{#gson}} import com.google.gson.Gson +import com.google.gson.GsonBuilder +import java.text.DateFormat {{/gson}} {{#jackson}} import com.fasterxml.jackson.databind.ObjectMapper @@ -22,8 +23,13 @@ import com.fasterxml.jackson.databind.ObjectMapper baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: {{#gson}}Gson{{/gson}}{{#jackson}}ObjectMapper{{/jackson}} = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) { + {{#gson}} + jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT, + {{/gson}} + {{#jackson}} + jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT, + {{/jackson}} + ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { {{#operation}} /** diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/ApiClient.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/ApiClient.kt.mustache index b852ac8ec1a1..51a0a5f504e5 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/ApiClient.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/ApiClient.kt.mustache @@ -1,50 +1,68 @@ package {{packageName}}.infrastructure + import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.request.* +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter +import io.ktor.client.request.request +import io.ktor.client.request.setBody import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent -import io.ktor.http.* -import io.ktor.http.content.ByteArrayContent -import io.ktor.http.content.OutgoingContent +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpMethod +import io.ktor.http.Parameters +import io.ktor.http.URLBuilder import io.ktor.http.content.PartData -import kotlin.Unit - +import io.ktor.http.encodeURLQueryComponent +import io.ktor.http.encodedPath +import io.ktor.http.takeFrom {{#gson}} -import com.google.gson.Gson -import java.nio.charset.StandardCharsets +import io.ktor.serialization.gson.* +import com.google.gson.GsonBuilder +import java.text.DateFormat {{/gson}} {{#jackson}} +import io.ktor.serialization.jackson.* +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.core.util.DefaultIndenter +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter {{/jackson}} - +import org.openapitools.client.auth.ApiKeyAuth +import org.openapitools.client.auth.Authentication +import org.openapitools.client.auth.HttpBasicAuth +import org.openapitools.client.auth.HttpBearerAuth +import org.openapitools.client.auth.OAuth import {{packageName}}.auth.* {{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: {{#gson}}Gson{{/gson}}{{#jackson}}ObjectMapper{{/jackson}}, + {{#gson}} + jsonBlock: GsonBuilder.() -> Unit = JSON_DEFAULT, + {{/gson}} + {{#jackson}} + jsonBlock: ObjectMapper.() -> Unit = JSON_DEFAULT, + {{/jackson}} ) { - private val serializer: JsonSerializer by lazy { - JsonSerializerImpl(json) - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { + {{#gson}} + gson { jsonBlock() } + {{/gson}} + {{#jackson}} + jackson { jsonBlock() } + {{/jackson}} + } httpClientConfig?.invoke(it) } } @@ -67,9 +85,24 @@ import {{packageName}}.auth.* {{/hasAuthMethods}} {{#nonPublicApi}}internal {{/nonPublicApi}}companion object { - const val BASE_URL = "{{{basePath}}}" - val JSON_DEFAULT = {{#gson}}Gson(){{/gson}}{{#jackson}}ObjectMapper(){{/jackson}} - protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) + const val BASE_URL = "{{{basePath}}}" + {{#gson}} + val JSON_DEFAULT : GsonBuilder.() -> Unit = { + setDateFormat(DateFormat.LONG) + setPrettyPrinting() + } + {{/gson}} + {{#jackson}} + val JSON_DEFAULT: ObjectMapper.() -> Unit = { + configure(SerializationFeature.INDENT_OUTPUT, true) + setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { + indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) + indentObjectsWith(DefaultIndenter(" ", "\n")) + }) + registerModule(JavaTimeModule()) + } + {{/jackson}} + protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } /** @@ -78,7 +111,7 @@ import {{packageName}}.auth.* * @param username Username */ fun setUsername(username: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? ?: throw Exception("No HTTP basic authentication configured") auth.username = username } @@ -89,7 +122,7 @@ import {{packageName}}.auth.* * @param password Password */ fun setPassword(password: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? ?: throw Exception("No HTTP basic authentication configured") auth.password = password } @@ -101,7 +134,7 @@ import {{packageName}}.auth.* * @param paramName The name of the API key parameter, or null or set the first key. */ fun setApiKey(apiKey: String, paramName: String? = null) { - val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth? + val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth? ?: throw Exception("No API key authentication configured") auth.apiKey = apiKey } @@ -113,7 +146,7 @@ import {{packageName}}.auth.* * @param paramName The name of the API key parameter, or null or set the first key. */ fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) { - val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth? + val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth? ?: throw Exception("No API key authentication configured") auth.apiKeyPrefix = apiKeyPrefix } @@ -124,7 +157,7 @@ import {{packageName}}.auth.* * @param accessToken Access token */ fun setAccessToken(accessToken: String) { - val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth? + val auth = authentications.values.firstOrNull { it is OAuth } as OAuth? ?: throw Exception("No OAuth2 authentication configured") auth.accessToken = accessToken } @@ -135,7 +168,7 @@ import {{packageName}}.auth.* * @param bearerToken The bearer token. */ fun setBearerToken(bearerToken: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth? + val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth? ?: throw Exception("No Bearer authentication configured") auth.bearerToken = bearerToken } @@ -148,18 +181,13 @@ import {{packageName}}.auth.* return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -172,8 +200,7 @@ import {{packageName}}.auth.* this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body - + setBody(body) } } @@ -199,13 +226,3 @@ import {{packageName}}.auth.* RequestMethod.OPTIONS -> HttpMethod.Options } } - -{{#gson}}private class JsonSerializerImpl(private val gson: Gson) : JsonSerializer { - override fun write(data: Any, contentType: ContentType): OutgoingContent = - ByteArrayContent(gson.toJson(data).toByteArray(StandardCharsets.UTF_8), contentType) -}{{/gson}} - -{{#jackson}}private class JsonSerializerImpl(private val objectMapper: ObjectMapper) : JsonSerializer { - override fun write(data: Any, contentType: ContentType): OutgoingContent = - ByteArrayContent(objectMapper.writeValueAsBytes(data), contentType) -}{{/jackson}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/HttpResponse.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/HttpResponse.kt.mustache index 12d265674611..87a68f3084e5 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/HttpResponse.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/infrastructure/HttpResponse.kt.mustache @@ -1,9 +1,9 @@ package {{packageName}}.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo {{#nonPublicApi}}internal {{/nonPublicApi}}open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ import io.ktor.http.isSuccess {{#nonPublicApi}}internal {{/nonPublicApi}}class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } {{#nonPublicApi}}internal {{/nonPublicApi}}class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache index be8b31644067..4ee453f29691 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache @@ -8,7 +8,6 @@ import {{packageName}}.infrastructure.* import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.serialization.json.Json import io.ktor.http.ParametersBuilder import kotlinx.serialization.* diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.kts.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.kts.mustache index 42826ffff641..797279d5d44f 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.kts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.kts.mustache @@ -8,10 +8,10 @@ plugins { group = "{{groupId}}" version = "{{artifactVersion}}" -val kotlin_version = "1.6.0" -val coroutines_version = "1.5.2" -val serialization_version = "1.3.0" -val ktor_version = "1.6.4" +val kotlin_version = "1.6.10" +val coroutines_version = "1.6.3" +val serialization_version = "1.3.3" +val ktor_version = "2.0.3" repositories { mavenCentral() @@ -30,9 +30,11 @@ kotlin { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version") + api("io.ktor:ktor-client-core:$ktor_version") - api("io.ktor:ktor-client-json:$ktor_version") api("io.ktor:ktor-client-serialization:$ktor_version") + api("io.ktor:ktor-client-content-negotiation:$ktor_version") + api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") } } diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClient.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClient.kt.mustache index 470c4bc29265..bc5d9b195081 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClient.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClient.kt.mustache @@ -3,43 +3,31 @@ package {{packageName}}.infrastructure import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.kotlinx.json.* import io.ktor.client.request.* import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent import io.ktor.http.* -import io.ktor.http.content.OutgoingContent import io.ktor.http.content.PartData import kotlin.Unit import kotlinx.serialization.json.Json -import {{apiPackage}}.* -import {{modelPackage}}.* import {{packageName}}.auth.* {{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - private val json: Json + private val jsonBlock: Json ) { - private val serializer: JsonSerializer by lazy { - KotlinxSerializer(json).ignoreOutgoingContent() - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { json(jsonBlock) } httpClientConfig?.invoke(it) } } @@ -63,7 +51,11 @@ import {{packageName}}.auth.* {{#nonPublicApi}}internal {{/nonPublicApi}}companion object { const val BASE_URL = "{{{basePath}}}" - val JSON_DEFAULT = Json { ignoreUnknownKeys = true } + val JSON_DEFAULT = Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } @@ -143,18 +135,13 @@ import {{packageName}}.auth.* return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -167,7 +154,7 @@ import {{packageName}}.auth.* this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body + this.setBody(body) } } @@ -193,14 +180,4 @@ import {{packageName}}.auth.* RequestMethod.POST -> HttpMethod.Post RequestMethod.OPTIONS -> HttpMethod.Options } -} - -// https://github.com/ktorio/ktor/issues/851 -private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this) - -private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate { - override fun write(data: Any): OutgoingContent { - if (data is OutgoingContent) return data - return delegate.write(data) - } -} +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache index 3ade97210cb0..39825fbe388b 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache @@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it private fun Int.toBase64(): Char = BASE64_ALPHABET[this] private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64() -internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes() +internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes() /** * Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes. diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache index 12d265674611..87a68f3084e5 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache @@ -1,9 +1,9 @@ package {{packageName}}.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo {{#nonPublicApi}}internal {{/nonPublicApi}}open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ import io.ktor.http.isSuccess {{#nonPublicApi}}internal {{/nonPublicApi}}class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } {{#nonPublicApi}}internal {{/nonPublicApi}}class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/samples/client/petstore/kotlin-allOff-discriminator/build.gradle b/samples/client/petstore/kotlin-allOff-discriminator/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-allOff-discriminator/build.gradle +++ b/samples/client/petstore/kotlin-allOff-discriminator/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp3/build.gradle b/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp3/build.gradle index b19a3b3873dc..e48744c81ed4 100644 --- a/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp3/build.gradle +++ b/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp3/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" implementation "com.squareup.okhttp3:okhttp:3.12.13" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp4/build.gradle b/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp4/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp4/build.gradle +++ b/samples/client/petstore/kotlin-array-simple-string-jvm-okhttp4/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-array-simple-string-multiplatform/build.gradle.kts b/samples/client/petstore/kotlin-array-simple-string-multiplatform/build.gradle.kts index 2380844aa924..219d79917c91 100644 --- a/samples/client/petstore/kotlin-array-simple-string-multiplatform/build.gradle.kts +++ b/samples/client/petstore/kotlin-array-simple-string-multiplatform/build.gradle.kts @@ -8,10 +8,10 @@ plugins { group = "org.openapitools" version = "1.0.0" -val kotlin_version = "1.6.0" -val coroutines_version = "1.5.2" -val serialization_version = "1.3.0" -val ktor_version = "1.6.4" +val kotlin_version = "1.6.10" +val coroutines_version = "1.6.3" +val serialization_version = "1.3.3" +val ktor_version = "2.0.3" repositories { mavenCentral() @@ -30,9 +30,11 @@ kotlin { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version") + api("io.ktor:ktor-client-core:$ktor_version") - api("io.ktor:ktor-client-json:$ktor_version") api("io.ktor:ktor-client-serialization:$ktor_version") + api("io.ktor:ktor-client-content-negotiation:$ktor_version") + api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") } } diff --git a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt index d79299bb11a5..567106aadbf0 100644 --- a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt +++ b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt @@ -25,7 +25,6 @@ import org.openapitools.client.infrastructure.* import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.serialization.json.Json import io.ktor.http.ParametersBuilder import kotlinx.serialization.* diff --git a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt index 77dc28c81460..fd07e4229d10 100644 --- a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.kotlinx.json.* import io.ktor.client.request.* import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent import io.ktor.http.* -import io.ktor.http.content.OutgoingContent import io.ktor.http.content.PartData import kotlin.Unit import kotlinx.serialization.json.Json -import org.openapitools.client.apis.* -import org.openapitools.client.models.* import org.openapitools.client.auth.* open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - private val json: Json + private val jsonBlock: Json ) { - private val serializer: JsonSerializer by lazy { - KotlinxSerializer(json).ignoreOutgoingContent() - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { json(jsonBlock) } httpClientConfig?.invoke(it) } } @@ -52,7 +40,11 @@ open class ApiClient( companion object { const val BASE_URL = "http://localhost" - val JSON_DEFAULT = Json { ignoreUnknownKeys = true } + val JSON_DEFAULT = Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } @@ -132,18 +124,13 @@ open class ApiClient( return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -156,7 +143,7 @@ open class ApiClient( this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body + this.setBody(body) } } @@ -182,14 +169,4 @@ open class ApiClient( RequestMethod.POST -> HttpMethod.Post RequestMethod.OPTIONS -> HttpMethod.Options } -} - -// https://github.com/ktorio/ktor/issues/851 -private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this) - -private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate { - override fun write(data: Any): OutgoingContent { - if (data is OutgoingContent) return data - return delegate.write(data) - } -} +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt index 7d30ce18fcf1..0ff85787389a 100644 --- a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt +++ b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt @@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it private fun Int.toBase64(): Char = BASE64_ALPHABET[this] private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64() -internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes() +internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes() /** * Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes. diff --git a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt index 61e55bc5b153..4285d605ea62 100644 --- a/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt +++ b/samples/client/petstore/kotlin-array-simple-string-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt @@ -1,9 +1,9 @@ package org.openapitools.client.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ interface BodyProvider { class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/build.gradle.kts b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/build.gradle.kts index 2380844aa924..219d79917c91 100644 --- a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/build.gradle.kts +++ b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/build.gradle.kts @@ -8,10 +8,10 @@ plugins { group = "org.openapitools" version = "1.0.0" -val kotlin_version = "1.6.0" -val coroutines_version = "1.5.2" -val serialization_version = "1.3.0" -val ktor_version = "1.6.4" +val kotlin_version = "1.6.10" +val coroutines_version = "1.6.3" +val serialization_version = "1.3.3" +val ktor_version = "2.0.3" repositories { mavenCentral() @@ -30,9 +30,11 @@ kotlin { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version") + api("io.ktor:ktor-client-core:$ktor_version") - api("io.ktor:ktor-client-json:$ktor_version") api("io.ktor:ktor-client-serialization:$ktor_version") + api("io.ktor:ktor-client-content-negotiation:$ktor_version") + api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") } } diff --git a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt index 8daf4379155e..ce791db9b5b5 100644 --- a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt +++ b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt @@ -26,7 +26,6 @@ import org.openapitools.client.infrastructure.* import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.serialization.json.Json import io.ktor.http.ParametersBuilder import kotlinx.serialization.* diff --git a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt index 77dc28c81460..fd07e4229d10 100644 --- a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.kotlinx.json.* import io.ktor.client.request.* import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent import io.ktor.http.* -import io.ktor.http.content.OutgoingContent import io.ktor.http.content.PartData import kotlin.Unit import kotlinx.serialization.json.Json -import org.openapitools.client.apis.* -import org.openapitools.client.models.* import org.openapitools.client.auth.* open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - private val json: Json + private val jsonBlock: Json ) { - private val serializer: JsonSerializer by lazy { - KotlinxSerializer(json).ignoreOutgoingContent() - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { json(jsonBlock) } httpClientConfig?.invoke(it) } } @@ -52,7 +40,11 @@ open class ApiClient( companion object { const val BASE_URL = "http://localhost" - val JSON_DEFAULT = Json { ignoreUnknownKeys = true } + val JSON_DEFAULT = Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } @@ -132,18 +124,13 @@ open class ApiClient( return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -156,7 +143,7 @@ open class ApiClient( this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body + this.setBody(body) } } @@ -182,14 +169,4 @@ open class ApiClient( RequestMethod.POST -> HttpMethod.Post RequestMethod.OPTIONS -> HttpMethod.Options } -} - -// https://github.com/ktorio/ktor/issues/851 -private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this) - -private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate { - override fun write(data: Any): OutgoingContent { - if (data is OutgoingContent) return data - return delegate.write(data) - } -} +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt index 7d30ce18fcf1..0ff85787389a 100644 --- a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt +++ b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt @@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it private fun Int.toBase64(): Char = BASE64_ALPHABET[this] private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64() -internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes() +internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes() /** * Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes. diff --git a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt index 61e55bc5b153..4285d605ea62 100644 --- a/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt +++ b/samples/client/petstore/kotlin-bigdecimal-default-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt @@ -1,9 +1,9 @@ package org.openapitools.client.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ interface BodyProvider { class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/samples/client/petstore/kotlin-bigdecimal-default-okhttp4/build.gradle b/samples/client/petstore/kotlin-bigdecimal-default-okhttp4/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-bigdecimal-default-okhttp4/build.gradle +++ b/samples/client/petstore/kotlin-bigdecimal-default-okhttp4/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-default-values-jvm-okhttp3/build.gradle b/samples/client/petstore/kotlin-default-values-jvm-okhttp3/build.gradle index b19a3b3873dc..e48744c81ed4 100644 --- a/samples/client/petstore/kotlin-default-values-jvm-okhttp3/build.gradle +++ b/samples/client/petstore/kotlin-default-values-jvm-okhttp3/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" implementation "com.squareup.okhttp3:okhttp:3.12.13" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-default-values-jvm-okhttp4/build.gradle b/samples/client/petstore/kotlin-default-values-jvm-okhttp4/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-default-values-jvm-okhttp4/build.gradle +++ b/samples/client/petstore/kotlin-default-values-jvm-okhttp4/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-default-values-jvm-retrofit2/build.gradle b/samples/client/petstore/kotlin-default-values-jvm-retrofit2/build.gradle index e094b704418f..07cd4614b28a 100644 --- a/samples/client/petstore/kotlin-default-values-jvm-retrofit2/build.gradle +++ b/samples/client/petstore/kotlin-default-values-jvm-retrofit2/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' ext.retrofitVersion = '2.9.0' repositories { @@ -31,9 +31,9 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:logging-interceptor:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:logging-interceptor:4.10.0" implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.squareup.retrofit2:converter-moshi:$retrofitVersion" implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersion" diff --git a/samples/client/petstore/kotlin-default-values-multiplatform/build.gradle.kts b/samples/client/petstore/kotlin-default-values-multiplatform/build.gradle.kts index 2380844aa924..219d79917c91 100644 --- a/samples/client/petstore/kotlin-default-values-multiplatform/build.gradle.kts +++ b/samples/client/petstore/kotlin-default-values-multiplatform/build.gradle.kts @@ -8,10 +8,10 @@ plugins { group = "org.openapitools" version = "1.0.0" -val kotlin_version = "1.6.0" -val coroutines_version = "1.5.2" -val serialization_version = "1.3.0" -val ktor_version = "1.6.4" +val kotlin_version = "1.6.10" +val coroutines_version = "1.6.3" +val serialization_version = "1.3.3" +val ktor_version = "2.0.3" repositories { mavenCentral() @@ -30,9 +30,11 @@ kotlin { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version") + api("io.ktor:ktor-client-core:$ktor_version") - api("io.ktor:ktor-client-json:$ktor_version") api("io.ktor:ktor-client-serialization:$ktor_version") + api("io.ktor:ktor-client-content-negotiation:$ktor_version") + api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") } } diff --git a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt index 6f47869c5a0a..a57053d08449 100644 --- a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt +++ b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt @@ -25,7 +25,6 @@ import org.openapitools.client.infrastructure.* import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.serialization.json.Json import io.ktor.http.ParametersBuilder import kotlinx.serialization.* diff --git a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt index 77dc28c81460..fd07e4229d10 100644 --- a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.kotlinx.json.* import io.ktor.client.request.* import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent import io.ktor.http.* -import io.ktor.http.content.OutgoingContent import io.ktor.http.content.PartData import kotlin.Unit import kotlinx.serialization.json.Json -import org.openapitools.client.apis.* -import org.openapitools.client.models.* import org.openapitools.client.auth.* open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - private val json: Json + private val jsonBlock: Json ) { - private val serializer: JsonSerializer by lazy { - KotlinxSerializer(json).ignoreOutgoingContent() - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { json(jsonBlock) } httpClientConfig?.invoke(it) } } @@ -52,7 +40,11 @@ open class ApiClient( companion object { const val BASE_URL = "http://localhost" - val JSON_DEFAULT = Json { ignoreUnknownKeys = true } + val JSON_DEFAULT = Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } @@ -132,18 +124,13 @@ open class ApiClient( return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -156,7 +143,7 @@ open class ApiClient( this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body + this.setBody(body) } } @@ -182,14 +169,4 @@ open class ApiClient( RequestMethod.POST -> HttpMethod.Post RequestMethod.OPTIONS -> HttpMethod.Options } -} - -// https://github.com/ktorio/ktor/issues/851 -private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this) - -private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate { - override fun write(data: Any): OutgoingContent { - if (data is OutgoingContent) return data - return delegate.write(data) - } -} +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt index 7d30ce18fcf1..0ff85787389a 100644 --- a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt +++ b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt @@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it private fun Int.toBase64(): Char = BASE64_ALPHABET[this] private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64() -internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes() +internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes() /** * Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes. diff --git a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt index 61e55bc5b153..4285d605ea62 100644 --- a/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt +++ b/samples/client/petstore/kotlin-default-values-multiplatform/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt @@ -1,9 +1,9 @@ package org.openapitools.client.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ interface BodyProvider { class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/samples/client/petstore/kotlin-enum-default-value/build.gradle b/samples/client/petstore/kotlin-enum-default-value/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-enum-default-value/build.gradle +++ b/samples/client/petstore/kotlin-enum-default-value/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-gson/build.gradle b/samples/client/petstore/kotlin-gson/build.gradle index 5cad8581cb64..205e3365af15 100644 --- a/samples/client/petstore/kotlin-gson/build.gradle +++ b/samples/client/petstore/kotlin-gson/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -29,7 +29,7 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "com.google.code.gson:gson:2.8.7" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.google.code.gson:gson:2.9.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-jackson/build.gradle b/samples/client/petstore/kotlin-jackson/build.gradle index 5cbe1fb014f9..e4d25c073cbd 100644 --- a/samples/client/petstore/kotlin-jackson/build.gradle +++ b/samples/client/petstore/kotlin-jackson/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { 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.12.3" - implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-json-request-string/build.gradle b/samples/client/petstore/kotlin-json-request-string/build.gradle index 602832bb2473..f495c77a7452 100644 --- a/samples/client/petstore/kotlin-json-request-string/build.gradle +++ b/samples/client/petstore/kotlin-json-request-string/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -32,8 +32,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-jvm-ktor-gson/build.gradle b/samples/client/petstore/kotlin-jvm-ktor-gson/build.gradle index 70cfaf2c98f1..0c3e6b64c92a 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-gson/build.gradle +++ b/samples/client/petstore/kotlin-jvm-ktor-gson/build.gradle @@ -2,13 +2,13 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' - ext.ktor_version = '1.6.7' + ext.kotlin_version = '1.6.10' + ext.ktor_version = '2.0.3' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,10 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "com.google.code.gson:gson:2.8.7" + implementation "com.google.code.gson:gson:2.9.0" implementation "io.ktor:ktor-client-core:$ktor_version" + implementation "io.ktor:ktor-client-content-negotiation:$ktor_version" + implementation "io.ktor:ktor-serialization-gson:$ktor_version" implementation "io.ktor:ktor-client-gson:$ktor_version" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt index 16778dcd2a91..a57d7bb3f4a7 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt @@ -28,15 +28,16 @@ import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine import io.ktor.http.ParametersBuilder - import com.google.gson.Gson +import com.google.gson.GsonBuilder +import java.text.DateFormat open class PetApi( baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: Gson = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) { + jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT, + ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { /** * Add a new pet to the store diff --git a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt index 4d6c90ef3087..af11d8184a29 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt @@ -27,15 +27,16 @@ import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine import io.ktor.http.ParametersBuilder - import com.google.gson.Gson +import com.google.gson.GsonBuilder +import java.text.DateFormat open class StoreApi( baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: Gson = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) { + jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT, + ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { /** * Delete purchase order by ID diff --git a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt index df392223264e..0e2a0d3dcb16 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt @@ -27,15 +27,16 @@ import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine import io.ktor.http.ParametersBuilder - import com.google.gson.Gson +import com.google.gson.GsonBuilder +import java.text.DateFormat open class UserApi( baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: Gson = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) { + jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT, + ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { /** * Create user diff --git a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt index 8a23111a84dc..5d6fc3af68b6 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -1,45 +1,47 @@ package org.openapitools.client.infrastructure + import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.request.* +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter +import io.ktor.client.request.request +import io.ktor.client.request.setBody import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent -import io.ktor.http.* -import io.ktor.http.content.ByteArrayContent -import io.ktor.http.content.OutgoingContent +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpMethod +import io.ktor.http.Parameters +import io.ktor.http.URLBuilder import io.ktor.http.content.PartData -import kotlin.Unit - -import com.google.gson.Gson -import java.nio.charset.StandardCharsets - +import io.ktor.http.encodeURLQueryComponent +import io.ktor.http.encodedPath +import io.ktor.http.takeFrom +import io.ktor.serialization.gson.* +import com.google.gson.GsonBuilder +import java.text.DateFormat +import org.openapitools.client.auth.ApiKeyAuth +import org.openapitools.client.auth.Authentication +import org.openapitools.client.auth.HttpBasicAuth +import org.openapitools.client.auth.HttpBearerAuth +import org.openapitools.client.auth.OAuth import org.openapitools.client.auth.* open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: Gson, + jsonBlock: GsonBuilder.() -> Unit = JSON_DEFAULT, ) { - private val serializer: JsonSerializer by lazy { - JsonSerializerImpl(json) - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { + gson { jsonBlock() } + } httpClientConfig?.invoke(it) } } @@ -55,9 +57,12 @@ open class ApiClient( } companion object { - const val BASE_URL = "http://petstore.swagger.io/v2" - val JSON_DEFAULT = Gson() - protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) + const val BASE_URL = "http://petstore.swagger.io/v2" + val JSON_DEFAULT : GsonBuilder.() -> Unit = { + setDateFormat(DateFormat.LONG) + setPrettyPrinting() + } + protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } /** @@ -66,7 +71,7 @@ open class ApiClient( * @param username Username */ fun setUsername(username: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? ?: throw Exception("No HTTP basic authentication configured") auth.username = username } @@ -77,7 +82,7 @@ open class ApiClient( * @param password Password */ fun setPassword(password: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? ?: throw Exception("No HTTP basic authentication configured") auth.password = password } @@ -89,7 +94,7 @@ open class ApiClient( * @param paramName The name of the API key parameter, or null or set the first key. */ fun setApiKey(apiKey: String, paramName: String? = null) { - val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth? + val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth? ?: throw Exception("No API key authentication configured") auth.apiKey = apiKey } @@ -101,7 +106,7 @@ open class ApiClient( * @param paramName The name of the API key parameter, or null or set the first key. */ fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) { - val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth? + val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth? ?: throw Exception("No API key authentication configured") auth.apiKeyPrefix = apiKeyPrefix } @@ -112,7 +117,7 @@ open class ApiClient( * @param accessToken Access token */ fun setAccessToken(accessToken: String) { - val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth? + val auth = authentications.values.firstOrNull { it is OAuth } as OAuth? ?: throw Exception("No OAuth2 authentication configured") auth.accessToken = accessToken } @@ -123,7 +128,7 @@ open class ApiClient( * @param bearerToken The bearer token. */ fun setBearerToken(bearerToken: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth? + val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth? ?: throw Exception("No Bearer authentication configured") auth.bearerToken = bearerToken } @@ -136,18 +141,13 @@ open class ApiClient( return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -160,8 +160,7 @@ open class ApiClient( this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body - + setBody(body) } } @@ -187,10 +186,3 @@ open class ApiClient( RequestMethod.OPTIONS -> HttpMethod.Options } } - -private class JsonSerializerImpl(private val gson: Gson) : JsonSerializer { - override fun write(data: Any, contentType: ContentType): OutgoingContent = - ByteArrayContent(gson.toJson(data).toByteArray(StandardCharsets.UTF_8), contentType) -} - - diff --git a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt index 61e55bc5b153..4285d605ea62 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-gson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt @@ -1,9 +1,9 @@ package org.openapitools.client.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ interface BodyProvider { class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/samples/client/petstore/kotlin-jvm-ktor-jackson/build.gradle b/samples/client/petstore/kotlin-jvm-ktor-jackson/build.gradle index a9de22fdf103..febcd440b1e9 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-jackson/build.gradle +++ b/samples/client/petstore/kotlin-jvm-ktor-jackson/build.gradle @@ -2,13 +2,13 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' - ext.ktor_version = '1.6.7' + ext.kotlin_version = '1.6.10' + ext.ktor_version = '2.0.3' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -31,9 +31,11 @@ test { 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.12.3" - implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3" + implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3" implementation "io.ktor:ktor-client-core:$ktor_version" + implementation "io.ktor:ktor-client-content-negotiation:$ktor_version" implementation "io.ktor:ktor-client-jackson:$ktor_version" + implementation "io.ktor:ktor-serialization-jackson:$ktor_version" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt index f1ae54f27451..6f7528a51784 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/PetApi.kt @@ -28,15 +28,14 @@ import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine import io.ktor.http.ParametersBuilder - import com.fasterxml.jackson.databind.ObjectMapper open class PetApi( baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: ObjectMapper = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) { + jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT, + ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { /** * Add a new pet to the store diff --git a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt index 17f13b366c3a..c5ed2f8ac42d 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt @@ -27,15 +27,14 @@ import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine import io.ktor.http.ParametersBuilder - import com.fasterxml.jackson.databind.ObjectMapper open class StoreApi( baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: ObjectMapper = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) { + jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT, + ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { /** * Delete purchase order by ID diff --git a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt index b65926f5fcb3..d19684bc8676 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/apis/UserApi.kt @@ -27,15 +27,14 @@ import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine import io.ktor.http.ParametersBuilder - import com.fasterxml.jackson.databind.ObjectMapper open class UserApi( baseUrl: String = ApiClient.BASE_URL, httpClientEngine: HttpClientEngine? = null, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: ObjectMapper = ApiClient.JSON_DEFAULT, - ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) { + jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT, + ) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) { /** * Create user diff --git a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt index f492c6e881a9..e21bccb90604 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -1,44 +1,51 @@ package org.openapitools.client.infrastructure + import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.request.* +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter +import io.ktor.client.request.request +import io.ktor.client.request.setBody import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent -import io.ktor.http.* -import io.ktor.http.content.ByteArrayContent -import io.ktor.http.content.OutgoingContent +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpMethod +import io.ktor.http.Parameters +import io.ktor.http.URLBuilder import io.ktor.http.content.PartData -import kotlin.Unit - +import io.ktor.http.encodeURLQueryComponent +import io.ktor.http.encodedPath +import io.ktor.http.takeFrom +import io.ktor.serialization.jackson.* +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.databind.ObjectMapper - +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.core.util.DefaultIndenter +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter +import org.openapitools.client.auth.ApiKeyAuth +import org.openapitools.client.auth.Authentication +import org.openapitools.client.auth.HttpBasicAuth +import org.openapitools.client.auth.HttpBearerAuth +import org.openapitools.client.auth.OAuth import org.openapitools.client.auth.* open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - json: ObjectMapper, + jsonBlock: ObjectMapper.() -> Unit = JSON_DEFAULT, ) { - private val serializer: JsonSerializer by lazy { - JsonSerializerImpl(json) - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { + jackson { jsonBlock() } + } httpClientConfig?.invoke(it) } } @@ -54,9 +61,16 @@ open class ApiClient( } companion object { - const val BASE_URL = "http://petstore.swagger.io/v2" - val JSON_DEFAULT = ObjectMapper() - protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) + const val BASE_URL = "http://petstore.swagger.io/v2" + val JSON_DEFAULT: ObjectMapper.() -> Unit = { + configure(SerializationFeature.INDENT_OUTPUT, true) + setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { + indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) + indentObjectsWith(DefaultIndenter(" ", "\n")) + }) + registerModule(JavaTimeModule()) + } + protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } /** @@ -65,7 +79,7 @@ open class ApiClient( * @param username Username */ fun setUsername(username: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? ?: throw Exception("No HTTP basic authentication configured") auth.username = username } @@ -76,7 +90,7 @@ open class ApiClient( * @param password Password */ fun setPassword(password: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? ?: throw Exception("No HTTP basic authentication configured") auth.password = password } @@ -88,7 +102,7 @@ open class ApiClient( * @param paramName The name of the API key parameter, or null or set the first key. */ fun setApiKey(apiKey: String, paramName: String? = null) { - val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth? + val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth? ?: throw Exception("No API key authentication configured") auth.apiKey = apiKey } @@ -100,7 +114,7 @@ open class ApiClient( * @param paramName The name of the API key parameter, or null or set the first key. */ fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) { - val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth? + val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth? ?: throw Exception("No API key authentication configured") auth.apiKeyPrefix = apiKeyPrefix } @@ -111,7 +125,7 @@ open class ApiClient( * @param accessToken Access token */ fun setAccessToken(accessToken: String) { - val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth? + val auth = authentications.values.firstOrNull { it is OAuth } as OAuth? ?: throw Exception("No OAuth2 authentication configured") auth.accessToken = accessToken } @@ -122,7 +136,7 @@ open class ApiClient( * @param bearerToken The bearer token. */ fun setBearerToken(bearerToken: String) { - val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth? + val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth? ?: throw Exception("No Bearer authentication configured") auth.bearerToken = bearerToken } @@ -135,18 +149,13 @@ open class ApiClient( return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -159,8 +168,7 @@ open class ApiClient( this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body - + setBody(body) } } @@ -186,10 +194,3 @@ open class ApiClient( RequestMethod.OPTIONS -> HttpMethod.Options } } - - - -private class JsonSerializerImpl(private val objectMapper: ObjectMapper) : JsonSerializer { - override fun write(data: Any, contentType: ContentType): OutgoingContent = - ByteArrayContent(objectMapper.writeValueAsBytes(data), contentType) -} diff --git a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt index 61e55bc5b153..4285d605ea62 100644 --- a/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt +++ b/samples/client/petstore/kotlin-jvm-ktor-jackson/src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt @@ -1,9 +1,9 @@ package org.openapitools.client.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ interface BodyProvider { class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle b/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle index 70d79ab69322..410fce57b481 100644 --- a/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle +++ b/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -29,8 +29,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1" - implementation "com.google.code.gson:gson:2.8.7" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3" + implementation "com.google.code.gson:gson:2.9.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-modelMutable/build.gradle b/samples/client/petstore/kotlin-modelMutable/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-modelMutable/build.gradle +++ b/samples/client/petstore/kotlin-modelMutable/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-moshi-codegen/build.gradle b/samples/client/petstore/kotlin-moshi-codegen/build.gradle index 7e8fe4d90390..1f5a719c9df9 100644 --- a/samples/client/petstore/kotlin-moshi-codegen/build.gradle +++ b/samples/client/petstore/kotlin-moshi-codegen/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,9 +30,9 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "com.squareup.moshi:moshi:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - kapt "com.squareup.moshi:moshi-kotlin-codegen:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-multiplatform/build.gradle.kts b/samples/client/petstore/kotlin-multiplatform/build.gradle.kts index 2380844aa924..219d79917c91 100644 --- a/samples/client/petstore/kotlin-multiplatform/build.gradle.kts +++ b/samples/client/petstore/kotlin-multiplatform/build.gradle.kts @@ -8,10 +8,10 @@ plugins { group = "org.openapitools" version = "1.0.0" -val kotlin_version = "1.6.0" -val coroutines_version = "1.5.2" -val serialization_version = "1.3.0" -val ktor_version = "1.6.4" +val kotlin_version = "1.6.10" +val coroutines_version = "1.6.3" +val serialization_version = "1.3.3" +val ktor_version = "2.0.3" repositories { mavenCentral() @@ -30,9 +30,11 @@ kotlin { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version") + api("io.ktor:ktor-client-core:$ktor_version") - api("io.ktor:ktor-client-json:$ktor_version") api("io.ktor:ktor-client-serialization:$ktor_version") + api("io.ktor:ktor-client-content-negotiation:$ktor_version") + api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") } } diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt index 5bfd90fd04c8..9433e84db8a6 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt @@ -27,7 +27,6 @@ import org.openapitools.client.infrastructure.* import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.serialization.json.Json import io.ktor.http.ParametersBuilder import kotlinx.serialization.* diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/StoreApi.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/StoreApi.kt index 1e3de76952bd..4be0e5910a79 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/StoreApi.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/StoreApi.kt @@ -26,7 +26,6 @@ import org.openapitools.client.infrastructure.* import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.serialization.json.Json import io.ktor.http.ParametersBuilder import kotlinx.serialization.* diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/UserApi.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/UserApi.kt index f1c1dc2e5f26..aa1e2250b323 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/UserApi.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/UserApi.kt @@ -26,7 +26,6 @@ import org.openapitools.client.infrastructure.* import io.ktor.client.HttpClientConfig import io.ktor.client.request.forms.formData import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.serialization.json.Json import io.ktor.http.ParametersBuilder import kotlinx.serialization.* diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt index a6ec2640afcf..dc660734191a 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.JsonSerializer -import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.kotlinx.json.* import io.ktor.client.request.* import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.header import io.ktor.client.request.parameter import io.ktor.client.statement.HttpResponse -import io.ktor.client.utils.EmptyContent import io.ktor.http.* -import io.ktor.http.content.OutgoingContent import io.ktor.http.content.PartData import kotlin.Unit import kotlinx.serialization.json.Json -import org.openapitools.client.apis.* -import org.openapitools.client.models.* import org.openapitools.client.auth.* open class ApiClient( private val baseUrl: String, httpClientEngine: HttpClientEngine?, httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, - private val json: Json + private val jsonBlock: Json ) { - private val serializer: JsonSerializer by lazy { - KotlinxSerializer(json).ignoreOutgoingContent() - } - private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { { - // Hold a reference to the serializer to avoid freezing the entire ApiClient instance - // when the JsonFeature is configured. - val serializerReference = serializer - it.install(JsonFeature) { serializer = serializerReference } + it.install(ContentNegotiation) { json(jsonBlock) } httpClientConfig?.invoke(it) } } @@ -56,7 +44,11 @@ open class ApiClient( companion object { const val BASE_URL = "http://petstore.swagger.io/v2" - val JSON_DEFAULT = Json { ignoreUnknownKeys = true } + val JSON_DEFAULT = Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) } @@ -136,18 +128,13 @@ open class ApiClient( return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) } - protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { - val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) } - ?: ContentType.Application.Json) - return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames) - else request(requestConfig, authNames = authNames) - } + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) - protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse { + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { requestConfig.updateForAuth(authNames) val headers = requestConfig.headers - return client.request { + return client.request { this.url { this.takeFrom(URLBuilder(baseUrl)) appendPath(requestConfig.path.trimStart('/').split('/')) @@ -160,7 +147,7 @@ open class ApiClient( this.method = requestConfig.method.httpMethod headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) - this.body = body + this.setBody(body) } } @@ -186,14 +173,4 @@ open class ApiClient( RequestMethod.POST -> HttpMethod.Post RequestMethod.OPTIONS -> HttpMethod.Options } -} - -// https://github.com/ktorio/ktor/issues/851 -private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this) - -private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate { - override fun write(data: Any): OutgoingContent { - if (data is OutgoingContent) return data - return delegate.write(data) - } -} +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/Bytes.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/Bytes.kt index 7d30ce18fcf1..0ff85787389a 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/Bytes.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/Bytes.kt @@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it private fun Int.toBase64(): Char = BASE64_ALPHABET[this] private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64() -internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes() +internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes() /** * Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes. diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt index 61e55bc5b153..4285d605ea62 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt @@ -1,9 +1,9 @@ package org.openapitools.client.infrastructure -import io.ktor.client.call.TypeInfo -import io.ktor.client.call.typeInfo import io.ktor.http.Headers import io.ktor.http.isSuccess +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) { val status: Int = response.status.value @@ -29,11 +29,11 @@ interface BodyProvider { class TypedBodyProvider(private val type: TypeInfo) : BodyProvider { @Suppress("UNCHECKED_CAST") override suspend fun body(response: io.ktor.client.statement.HttpResponse): T = - response.call.receive(type) as T + response.call.body(type) as T @Suppress("UNCHECKED_CAST") override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V = - response.call.receive(type) as V + response.call.body(type) as V } class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider { diff --git a/samples/client/petstore/kotlin-nonpublic/build.gradle b/samples/client/petstore/kotlin-nonpublic/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-nonpublic/build.gradle +++ b/samples/client/petstore/kotlin-nonpublic/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-nullable/build.gradle b/samples/client/petstore/kotlin-nullable/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-nullable/build.gradle +++ b/samples/client/petstore/kotlin-nullable/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-okhttp3/build.gradle b/samples/client/petstore/kotlin-okhttp3/build.gradle index b19a3b3873dc..e48744c81ed4 100644 --- a/samples/client/petstore/kotlin-okhttp3/build.gradle +++ b/samples/client/petstore/kotlin-okhttp3/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" implementation "com.squareup.okhttp3:okhttp:3.12.13" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-retrofit2-kotlinx_serialization/build.gradle b/samples/client/petstore/kotlin-retrofit2-kotlinx_serialization/build.gradle index 60257e316011..e94a5d013012 100644 --- a/samples/client/petstore/kotlin-retrofit2-kotlinx_serialization/build.gradle +++ b/samples/client/petstore/kotlin-retrofit2-kotlinx_serialization/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' ext.retrofitVersion = '2.9.0' repositories { @@ -32,9 +32,9 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3" implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2" - implementation "com.squareup.okhttp3:logging-interceptor:4.9.1" + implementation "com.squareup.okhttp3:logging-interceptor:4.10.0" implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0" implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersion" diff --git a/samples/client/petstore/kotlin-retrofit2-rx3/build.gradle b/samples/client/petstore/kotlin-retrofit2-rx3/build.gradle index 0d9707eb2d9b..8d3c9dd1bd27 100644 --- a/samples/client/petstore/kotlin-retrofit2-rx3/build.gradle +++ b/samples/client/petstore/kotlin-retrofit2-rx3/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' ext.retrofitVersion = '2.9.0' ext.rxJava3Version = '3.0.12' @@ -32,10 +32,10 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2" - implementation "com.squareup.okhttp3:logging-interceptor:4.9.1" + implementation "com.squareup.okhttp3:logging-interceptor:4.10.0" implementation "io.reactivex.rxjava3:rxjava:$rxJava3Version" implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0" implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" diff --git a/samples/client/petstore/kotlin-retrofit2/build.gradle b/samples/client/petstore/kotlin-retrofit2/build.gradle index 32e67f975a8b..2c2228d9d6ed 100644 --- a/samples/client/petstore/kotlin-retrofit2/build.gradle +++ b/samples/client/petstore/kotlin-retrofit2/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' ext.retrofitVersion = '2.9.0' repositories { @@ -31,10 +31,10 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2" - implementation "com.squareup.okhttp3:logging-interceptor:4.9.1" + implementation "com.squareup.okhttp3:logging-interceptor:4.10.0" implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.squareup.retrofit2:converter-moshi:$retrofitVersion" implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersion" diff --git a/samples/client/petstore/kotlin-string/build.gradle b/samples/client/petstore/kotlin-string/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin-string/build.gradle +++ b/samples/client/petstore/kotlin-string/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-threetenbp/build.gradle b/samples/client/petstore/kotlin-threetenbp/build.gradle index 39e3e411643f..e27847c2f330 100644 --- a/samples/client/petstore/kotlin-threetenbp/build.gradle +++ b/samples/client/petstore/kotlin-threetenbp/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,9 +30,9 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" implementation "org.threeten:threetenbp:1.5.1" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin-uppercase-enum/build.gradle b/samples/client/petstore/kotlin-uppercase-enum/build.gradle index 41109c8e0108..1df0362d6c86 100644 --- a/samples/client/petstore/kotlin-uppercase-enum/build.gradle +++ b/samples/client/petstore/kotlin-uppercase-enum/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -31,8 +31,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/client/petstore/kotlin/build.gradle b/samples/client/petstore/kotlin/build.gradle index 3de8b45b135e..527140cfc854 100644 --- a/samples/client/petstore/kotlin/build.gradle +++ b/samples/client/petstore/kotlin/build.gradle @@ -2,12 +2,12 @@ group 'org.openapitools' version '1.0.0' wrapper { - gradleVersion = '6.8.3' + gradleVersion = '7.5' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.10' repositories { maven { url "https://repo1.maven.org/maven2" } @@ -30,8 +30,8 @@ test { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.moshi:moshi-adapters:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.moshi:moshi-kotlin:1.13.0" + implementation "com.squareup.moshi:moshi-adapters:1.13.0" + implementation "com.squareup.okhttp3:okhttp:4.10.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" } diff --git a/samples/server/petstore/python-blueplanet/app/openapi_server/typing_utils.py b/samples/server/petstore/python-blueplanet/app/openapi_server/typing_utils.py index 0563f81fd534..e69de29bb2d1 100644 --- a/samples/server/petstore/python-blueplanet/app/openapi_server/typing_utils.py +++ b/samples/server/petstore/python-blueplanet/app/openapi_server/typing_utils.py @@ -1,32 +0,0 @@ -# coding: utf-8 - -import sys - -if sys.version_info < (3, 7): - import typing - - def is_generic(klass): - """ Determine whether klass is a generic class """ - return type(klass) == typing.GenericMeta - - def is_dict(klass): - """ Determine whether klass is a Dict """ - return klass.__extra__ == dict - - def is_list(klass): - """ Determine whether klass is a List """ - return klass.__extra__ == list - -else: - - def is_generic(klass): - """ Determine whether klass is a generic class """ - return hasattr(klass, '__origin__') - - def is_dict(klass): - """ Determine whether klass is a Dict """ - return klass.__origin__ == dict - - def is_list(klass): - """ Determine whether klass is a List """ - return klass.__origin__ == list