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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bin/configs/kotlin-json-request-string.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ additionalProperties:
artifactId: kotlin-petstore-json-request-string
parcelizeModels: true
supportAndroidApiLevel25AndBelow: true
serializationLibrary: kotlinx_serialization
enumUnknownDefaultCase: "true"
2 changes: 2 additions & 0 deletions bin/configs/kotlin-uppercase-enum.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ templateDir: modules/openapi-generator/src/main/resources/kotlin-client
additionalProperties:
artifactId: kotlin-uppercase-enum
enumPropertyNaming: UPPERCASE
serializationLibrary: kotlinx_serialization
enumUnknownDefaultCase: "true"
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo
import {{#serializableModel}}kotlinx.serialization.Serializable as KSerializable{{/serializableModel}}{{^serializableModel}}kotlinx.serialization.Serializable{{/serializableModel}}
import kotlinx.serialization.SerialName
import kotlinx.serialization.Contextual
{{#enumUnknownDefaultCase}}
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
{{/enumUnknownDefaultCase}}
{{#hasEnums}}
{{/hasEnums}}
{{/kotlinx_serialization}}
Expand Down Expand Up @@ -88,7 +95,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
*/
{{^multiplatform}}
{{#kotlinx_serialization}}
{{#serializableModel}}@KSerializable{{/serializableModel}}{{^serializableModel}}@Serializable{{/serializableModel}}
{{#serializableModel}}@KSerializable{{/serializableModel}}{{^serializableModel}}@Serializable{{#enumUnknownDefaultCase}}(with = {{classname}}Serializer::class){{/enumUnknownDefaultCase}}{{/serializableModel}}
{{/kotlinx_serialization}}
{{/multiplatform}}
{{#multiplatform}}
Expand Down Expand Up @@ -116,7 +123,22 @@ import {{packageName}}.infrastructure.ITransformForStorage
{{/multiplatform}}
{{/enumVars}}
{{/allowableValues}}
}
}{{#kotlinx_serialization}}{{#enumUnknownDefaultCase}}

@Serializer(forClass = {{{nameInCamelCase}}}::class)
internal object {{nameInCamelCase}}Serializer : KSerializer<{{nameInCamelCase}}> {
override val descriptor = {{{dataType}}}.serializer().descriptor

override fun deserialize(decoder: Decoder): {{nameInCamelCase}} {
val value = decoder.decodeSerializableValue({{{dataType}}}.serializer())
return {{nameInCamelCase}}.values().firstOrNull { it.value == value }
?: {{nameInCamelCase}}.{{#allowableValues}}{{#enumVars}}{{#-last}}{{&name}}{{/-last}}{{/enumVars}}{{/allowableValues}}
}

override fun serialize(encoder: Encoder, value: {{nameInCamelCase}}) {
encoder.encodeSerializableValue({{{dataType}}}.serializer(), value.value)
}
}{{/enumUnknownDefaultCase}}{{/kotlinx_serialization}}
{{/isEnum}}
{{/vars}}
{{/hasEnums}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ import com.fasterxml.jackson.annotation.JsonProperty
{{#kotlinx_serialization}}
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
{{#enumUnknownDefaultCase}}
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
{{/enumUnknownDefaultCase}}
{{/kotlinx_serialization}}
{{/multiplatform}}
{{#multiplatform}}
Expand All @@ -22,7 +29,7 @@ import kotlinx.serialization.*
*
* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/
{{#multiplatform}}@Serializable{{/multiplatform}}{{#kotlinx_serialization}}@Serializable{{/kotlinx_serialization}}
{{#multiplatform}}@Serializable{{/multiplatform}}{{#kotlinx_serialization}}@Serializable{{#enumUnknownDefaultCase}}(with = {{classname}}Serializer::class){{/enumUnknownDefaultCase}}{{/kotlinx_serialization}}
{{#nonPublicApi}}internal {{/nonPublicApi}}enum class {{classname}}(val value: {{{dataType}}}) {
{{#allowableValues}}{{#enumVars}}
{{^multiplatform}}
Expand Down Expand Up @@ -79,4 +86,19 @@ import kotlinx.serialization.*
}
}
}
}
}{{#kotlinx_serialization}}{{#enumUnknownDefaultCase}}

@Serializer(forClass = {{classname}}::class)
internal object {{classname}}Serializer : KSerializer<{{classname}}> {
override val descriptor = {{{dataType}}}.serializer().descriptor

override fun deserialize(decoder: Decoder): {{classname}} {
val value = decoder.decodeSerializableValue({{{dataType}}}.serializer())
return {{classname}}.values().firstOrNull { it.value == value }
?: {{classname}}.{{#allowableValues}}{{#enumVars}}{{#-last}}{{&name}}{{/-last}}{{/enumVars}}{{/allowableValues}}
}

override fun serialize(encoder: Encoder, value: {{classname}}) {
encoder.encodeSerializableValue({{{dataType}}}.serializer(), value.value)
}
}{{/enumUnknownDefaultCase}}{{/kotlinx_serialization}}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import org.threeten.bp.format.DateTimeFormatter
{{/gson}}
{{#kotlinx_serialization}}
@Serializer(forClass = LocalDate::class)
object LocalDateAdapter : KSerializer<LocalDate> {
{{#nonPublicApi}}internal {{/nonPublicApi}}object LocalDateAdapter : KSerializer<LocalDate> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: LocalDate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import org.threeten.bp.format.DateTimeFormatter
{{/gson}}
{{#kotlinx_serialization}}
@Serializer(forClass = LocalDateTime::class)
object LocalDateTimeAdapter : KSerializer<LocalDateTime> {
{{#nonPublicApi}}internal {{/nonPublicApi}}object LocalDateTimeAdapter : KSerializer<LocalDateTime> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: LocalDateTime) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import org.threeten.bp.format.DateTimeFormatter
{{/gson}}
{{#kotlinx_serialization}}
@Serializer(forClass = OffsetDateTime::class)
object OffsetDateTimeAdapter : KSerializer<OffsetDateTime> {
{{#nonPublicApi}}internal {{/nonPublicApi}}object OffsetDateTimeAdapter : KSerializer<OffsetDateTime> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("OffsetDateTime", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: OffsetDateTime) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,13 @@ import java.util.concurrent.atomic.AtomicLong
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
{{/jackson}}
{{#kotlinx_serialization}}
@Deprecated("Use Serializer.kotlinxSerializationAdapters instead", replaceWith = ReplaceWith("Serializer.kotlinxSerializationAdapters"))
@JvmStatic
val kotlinSerializationAdapters = SerializersModule {
val kotlinSerializationAdapters: SerializersModule
get() { return kotlinxSerializationAdapters }

@JvmStatic
val kotlinxSerializationAdapters = SerializersModule {
contextual(BigDecimal::class, BigDecimalAdapter)
contextual(BigInteger::class, BigIntegerAdapter)
contextual(LocalDate::class, LocalDateAdapter)
Expand All @@ -114,7 +119,18 @@ import java.util.concurrent.atomic.AtomicLong
contextual(StringBuilder::class, StringBuilderAdapter)
}

@Deprecated("Use Serializer.kotlinxSerializationJson instead", replaceWith = ReplaceWith("Serializer.kotlinxSerializationJson"))
@JvmStatic
val jvmJson: Json by lazy { Json { serializersModule = kotlinSerializationAdapters } }
val jvmJson: Json
get() { return kotlinxSerializationJson }

@JvmStatic
val kotlinxSerializationJson: Json by lazy {
Json {
serializersModule = kotlinxSerializationAdapters
ignoreUnknownKeys = true
isLenient = true
}
}
{{/kotlinx_serialization}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import java.net.URI
{{/moshi}}
{{#kotlinx_serialization}}
@Serializer(forClass = URI::class)
object URIAdapter : KSerializer<URI> {
{{#nonPublicApi}}internal {{/nonPublicApi}}object URIAdapter : KSerializer<URI> {
override fun serialize(encoder: Encoder, value: URI) {
encoder.encodeString(value.toASCIIString())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import java.util.UUID
{{/moshi}}
{{#kotlinx_serialization}}
@Serializer(forClass = UUID::class)
object UUIDAdapter : KSerializer<UUID> {
{{#nonPublicApi}}internal {{/nonPublicApi}}object UUIDAdapter : KSerializer<UUID> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: UUID) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ import com.squareup.moshi.adapter
MediaType.parse(mediaType ?: JsonMediaType), Serializer.jacksonObjectMapper.writeValueAsString(content)
{{/jackson}}
{{#kotlinx_serialization}}
MediaType.parse(mediaType ?: JsonMediaType), Serializer.jvmJson.encodeToString(content)
MediaType.parse(mediaType ?: JsonMediaType), Serializer.kotlinxSerializationJson.encodeToString(content)
{{/kotlinx_serialization}}
)
}
Expand All @@ -188,7 +188,7 @@ import com.squareup.moshi.adapter
Serializer.jacksonObjectMapper.writeValueAsString(content)
{{/jackson}}
{{#kotlinx_serialization}}
Serializer.jvmJson.encodeToString(content)
Serializer.kotlinxSerializationJson.encodeToString(content)
{{/kotlinx_serialization}}
.toRequestBody((mediaType ?: JsonMediaType).toMediaTypeOrNull())
}
Expand Down Expand Up @@ -236,7 +236,7 @@ import com.squareup.moshi.adapter
{{#moshi}}Serializer.moshi.adapter<T>().fromJson(bodyContent){{/moshi}}{{!
}}{{#gson}}Serializer.gson.fromJson(bodyContent, (object: TypeToken<T>(){}).getType()){{/gson}}{{!
}}{{#jackson}}Serializer.jacksonObjectMapper.readValue(bodyContent, object: TypeReference<T>() {}){{/jackson}}{{!
}}{{#kotlinx_serialization}}Serializer.jvmJson.decodeFromString<T>(bodyContent){{/kotlinx_serialization}}
}}{{#kotlinx_serialization}}Serializer.kotlinxSerializationJson.decodeFromString<T>(bodyContent){{/kotlinx_serialization}}
else -> throw UnsupportedOperationException("responseBody currently only supports JSON body.")
}
}
Expand Down Expand Up @@ -432,7 +432,7 @@ import com.squareup.moshi.adapter
return Serializer.jacksonObjectMapper.writeValueAsString(value).replace("\"", "")
{{/jackson}}
{{#kotlinx_serialization}}
return Serializer.jvmJson.encodeToString(value).replace("\"", "")
return Serializer.kotlinxSerializationJson.encodeToString(value).replace("\"", "")
{{/kotlinx_serialization}}
{{/toJson}}
{{^toJson}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import retrofit2.converter.moshi.MoshiConverterFactory

{{#kotlinx_serialization}}
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import {{packageName}}.infrastructure.Serializer.jvmJson
import {{packageName}}.infrastructure.Serializer.kotlinxSerializationJson
import okhttp3.MediaType.Companion.toMediaType
{{/kotlinx_serialization}}

Expand Down Expand Up @@ -84,7 +84,7 @@ import okhttp3.MediaType.Companion.toMediaType
.addConverterFactory(MoshiConverterFactory.create(serializerBuilder.build()))
{{/moshi}}
{{#kotlinx_serialization}}
.addConverterFactory(jvmJson.asConverterFactory("application/json".toMediaType()))
.addConverterFactory(kotlinxSerializationJson.asConverterFactory("application/json".toMediaType()))
{{/kotlinx_serialization}}
.apply {
if (converterFactory != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties
gradlew
gradlew.bat
proguard-rules.pro
settings.gradle
src/main/kotlin/org/openapitools/client/apis/PetApi.kt
src/main/kotlin/org/openapitools/client/apis/StoreApi.kt
src/main/kotlin/org/openapitools/client/apis/UserApi.kt
src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt
src/main/kotlin/org/openapitools/client/infrastructure/AtomicBooleanAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/AtomicIntegerAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/AtomicLongAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt
src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt
Expand All @@ -32,7 +35,9 @@ src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt
src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
src/main/kotlin/org/openapitools/client/infrastructure/StringBuilderAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/URLAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt
src/main/kotlin/org/openapitools/client/models/Category.kt
src/main/kotlin/org/openapitools/client/models/ModelApiResponse.kt
Expand Down
12 changes: 9 additions & 3 deletions samples/client/petstore/kotlin-json-request-string/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ buildscript {
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlinx-serialization'

repositories {
maven { url "https://repo1.maven.org/maven2" }
Expand All @@ -30,9 +32,13 @@ 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 "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1"
implementation "com.squareup.okhttp3:okhttp:4.9.1"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
freeCompilerArgs += "-Xopt-in=kotlinx.serialization.ExperimentalSerializationApi"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt # core serialization annotations

# kotlinx-serialization-json specific. Add this if you have java.lang.NoClassDefFoundError kotlinx.serialization.json.JsonObjectSerializer
-keepclassmembers class kotlinx.serialization.json.** { *** Companion; }
-keepclasseswithmembers class kotlinx.serialization.json.** { kotlinx.serialization.KSerializer serializer(...); }

# project specific.
-keep,includedescriptorclasses class org.openapitools.client.models.**$$serializer { *; }
-keepclassmembers class org.openapitools.client.models.** { *** Companion; }
-keepclasseswithmembers class org.openapitools.client.models.** { kotlinx.serialization.KSerializer serializer(...); }
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import okhttp3.OkHttpClient
import org.openapitools.client.models.ModelApiResponse
import org.openapitools.client.models.Pet

import com.squareup.moshi.Json
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ApiResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import okhttp3.OkHttpClient

import org.openapitools.client.models.Order

import com.squareup.moshi.Json
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ApiResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import okhttp3.OkHttpClient

import org.openapitools.client.models.User

import com.squareup.moshi.Json
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ApiResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.OffsetTime
import java.util.Locale
import com.squareup.moshi.adapter
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString

open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClient) {
companion object {
Expand Down Expand Up @@ -105,15 +106,14 @@ open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClie
if (content == null) {
EMPTY_REQUEST
} else {
Serializer.moshi.adapter(T::class.java).toJson(content)
Serializer.kotlinxSerializationJson.encodeToString(content)
.toRequestBody((mediaType ?: JsonMediaType).toMediaTypeOrNull())
}
mediaType == XmlMediaType -> throw UnsupportedOperationException("xml not currently supported.")
// TODO: this should be extended with other serializers
else -> throw UnsupportedOperationException("requestBody currently only supports JSON body and File body.")
}

@OptIn(ExperimentalStdlibApi::class)
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
if(body == null) {
return null
Expand All @@ -140,7 +140,7 @@ open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClie
}
return when {
mediaType==null || (mediaType.startsWith("application/") && mediaType.endsWith("json")) ->
Serializer.moshi.adapter<T>().fromJson(bodyContent)
Serializer.kotlinxSerializationJson.decodeFromString<T>(bodyContent)
else -> throw UnsupportedOperationException("responseBody currently only supports JSON body.")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.openapitools.client.infrastructure

import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.SerialDescriptor
import java.util.concurrent.atomic.AtomicBoolean

@Serializer(forClass = AtomicBoolean::class)
object AtomicBooleanAdapter : KSerializer<AtomicBoolean> {
override fun serialize(encoder: Encoder, value: AtomicBoolean) {
encoder.encodeBoolean(value.get())
}

override fun deserialize(decoder: Decoder): AtomicBoolean = AtomicBoolean(decoder.decodeBoolean())

override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("AtomicBoolean", PrimitiveKind.BOOLEAN)
}
Loading