From 541a75a10f2adbbc3c374cee73631b8231797b6e Mon Sep 17 00:00:00 2001 From: "Siret, Loic" Date: Fri, 7 Aug 2020 15:28:50 -0400 Subject: [PATCH 1/2] Add polymorphic support for Gson Based on Java-Gson generator --- .../kotlin-client/build.gradle.mustache | 1 + .../infrastructure/Serializer.kt.mustache | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) 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 a81f05ba3523..8cec3dbe7f3d 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 @@ -57,6 +57,7 @@ dependencies { {{/moshi}} {{#gson}} compile "com.google.code.gson:gson:2.8.6" + compile "io.gsonfire:gson-fire:1.8.0" {{/gson}} {{#jackson}} compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.2" diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache index 7ccd50796773..8bf29753008b 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache @@ -10,6 +10,9 @@ import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory {{#gson}} import com.google.gson.Gson import com.google.gson.GsonBuilder +import com.google.gson.JsonElement +import io.gsonfire.GsonFireBuilder +import io.gsonfire.TypeSelector {{^threetenbp}} import java.time.LocalDate import java.time.LocalDateTime @@ -21,6 +24,14 @@ import org.threeten.bp.LocalDateTime import org.threeten.bp.OffsetDateTime {{/threetenbp}} import java.util.UUID +{{#models.0}} +import {{modelPackage}}.* +{{/models.0}} +import kotlin.collections.HashMap +import kotlin.collections.MutableMap +import kotlin.collections.get +import kotlin.collections.set +import kotlin.collections.toTypedArray {{/gson}} {{#jackson}} import com.fasterxml.jackson.databind.ObjectMapper @@ -53,17 +64,46 @@ import java.util.Date {{/moshi}} {{#gson}} @JvmStatic - val gsonBuilder: GsonBuilder = GsonBuilder() + var gsonBuilder = GsonFireBuilder() + {{#models}}{{#model}}{{#discriminator}} + .registerTypeSelector<{{classname}}>({{classname}}::class.java, TypeSelector<{{classname}}?> { readElement -> + val classByDiscriminatorValue: MutableMap = HashMap() + {{#mappedModels}} + classByDiscriminatorValue["{{mappingName}}".toUpperCase()] = {{modelName}}::class.java + {{/mappedModels}} + + try { + return@TypeSelector getClassByDiscriminator( + classByDiscriminatorValue, + getDiscriminatorValue(readElement, "{{propertyName}}")) as Class? + } catch (ex: IllegalArgumentException) { return@TypeSelector {{classname}}::class.java} + }) + {{/discriminator}}{{/model}}{{/models}} + .createGsonBuilder() .registerTypeAdapter(Date::class.java, DateAdapter()) .registerTypeAdapter(OffsetDateTime::class.java, OffsetDateTimeAdapter()) .registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter()) .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) .registerTypeAdapter(ByteArray::class.java, ByteArrayAdapter()) - + @JvmStatic val gson: Gson by lazy { gsonBuilder.create() } + + fun getDiscriminatorValue(readElement: JsonElement, discriminatorField: String?): String? { + val element: JsonElement = readElement.getAsJsonObject().get(discriminatorField) + ?: throw IllegalArgumentException("missing discriminator field: <$discriminatorField>") + return element.getAsString() + } + + fun getClassByDiscriminator( + classByDiscriminatorValue: Map<*, *>, + discriminatorValue: String? + ): Class<*>? { + return classByDiscriminatorValue[discriminatorValue?.toUpperCase()] as Class<*>? + ?: throw IllegalArgumentException("cannot determine model class of name: <$discriminatorValue>") + } {{/gson}} {{#jackson}} @JvmStatic From 2b770737af754331bf3d790ec668ded136774cc5 Mon Sep 17 00:00:00 2001 From: "Siret, Loic" Date: Fri, 7 Aug 2020 16:15:47 -0400 Subject: [PATCH 2/2] Running ./bin/generate-samples.sh --- .../infrastructure/Serializer.kt.mustache | 6 ++-- .../client/petstore/kotlin-gson/build.gradle | 1 + .../client/infrastructure/Serializer.kt | 28 +++++++++++++++++-- .../build.gradle | 1 + .../client/infrastructure/Serializer.kt | 28 +++++++++++++++++-- 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache index 8bf29753008b..36e9f2cb8edd 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache @@ -64,8 +64,7 @@ import java.util.Date {{/moshi}} {{#gson}} @JvmStatic - var gsonBuilder = GsonFireBuilder() - {{#models}}{{#model}}{{#discriminator}} + var gsonBuilder = GsonFireBuilder(){{#models}}{{#model}}{{#discriminator}} .registerTypeSelector<{{classname}}>({{classname}}::class.java, TypeSelector<{{classname}}?> { readElement -> val classByDiscriminatorValue: MutableMap = HashMap() {{#mappedModels}} @@ -77,8 +76,7 @@ import java.util.Date classByDiscriminatorValue, getDiscriminatorValue(readElement, "{{propertyName}}")) as Class? } catch (ex: IllegalArgumentException) { return@TypeSelector {{classname}}::class.java} - }) - {{/discriminator}}{{/model}}{{/models}} + }){{/discriminator}}{{/model}}{{/models}} .createGsonBuilder() .registerTypeAdapter(Date::class.java, DateAdapter()) .registerTypeAdapter(OffsetDateTime::class.java, OffsetDateTimeAdapter()) diff --git a/samples/client/petstore/kotlin-gson/build.gradle b/samples/client/petstore/kotlin-gson/build.gradle index ce9cb568dd7b..87b688f40b4f 100644 --- a/samples/client/petstore/kotlin-gson/build.gradle +++ b/samples/client/petstore/kotlin-gson/build.gradle @@ -30,6 +30,7 @@ test { dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" compile "com.google.code.gson:gson:2.8.6" + compile "io.gsonfire:gson-fire:1.8.0" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "com.squareup.okhttp3:okhttp:4.2.2" testCompile "io.kotlintest:kotlintest-runner-junit5:3.1.0" diff --git a/samples/client/petstore/kotlin-gson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-gson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6465f1485531..a126a580bfa5 100644 --- a/samples/client/petstore/kotlin-gson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-gson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -2,23 +2,47 @@ package org.openapitools.client.infrastructure import com.google.gson.Gson import com.google.gson.GsonBuilder +import com.google.gson.JsonElement +import io.gsonfire.GsonFireBuilder +import io.gsonfire.TypeSelector import java.time.LocalDate import java.time.LocalDateTime import java.time.OffsetDateTime import java.util.UUID +import org.openapitools.client.models.* +import kotlin.collections.HashMap +import kotlin.collections.MutableMap +import kotlin.collections.get +import kotlin.collections.set +import kotlin.collections.toTypedArray import java.util.Date object Serializer { @JvmStatic - val gsonBuilder: GsonBuilder = GsonBuilder() + var gsonBuilder = GsonFireBuilder() + .createGsonBuilder() .registerTypeAdapter(Date::class.java, DateAdapter()) .registerTypeAdapter(OffsetDateTime::class.java, OffsetDateTimeAdapter()) .registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter()) .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) .registerTypeAdapter(ByteArray::class.java, ByteArrayAdapter()) - + @JvmStatic val gson: Gson by lazy { gsonBuilder.create() } + + fun getDiscriminatorValue(readElement: JsonElement, discriminatorField: String?): String? { + val element: JsonElement = readElement.getAsJsonObject().get(discriminatorField) + ?: throw IllegalArgumentException("missing discriminator field: <$discriminatorField>") + return element.getAsString() + } + + fun getClassByDiscriminator( + classByDiscriminatorValue: Map<*, *>, + discriminatorValue: String? + ): Class<*>? { + return classByDiscriminatorValue[discriminatorValue?.toUpperCase()] as Class<*>? + ?: throw IllegalArgumentException("cannot determine model class of name: <$discriminatorValue>") + } } diff --git a/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle b/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle index ce9cb568dd7b..87b688f40b4f 100644 --- a/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle +++ b/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/build.gradle @@ -30,6 +30,7 @@ test { dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" compile "com.google.code.gson:gson:2.8.6" + compile "io.gsonfire:gson-fire:1.8.0" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "com.squareup.okhttp3:okhttp:4.2.2" testCompile "io.kotlintest:kotlintest-runner-junit5:3.1.0" diff --git a/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6465f1485531..a126a580bfa5 100644 --- a/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jvm-okhttp4-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -2,23 +2,47 @@ package org.openapitools.client.infrastructure import com.google.gson.Gson import com.google.gson.GsonBuilder +import com.google.gson.JsonElement +import io.gsonfire.GsonFireBuilder +import io.gsonfire.TypeSelector import java.time.LocalDate import java.time.LocalDateTime import java.time.OffsetDateTime import java.util.UUID +import org.openapitools.client.models.* +import kotlin.collections.HashMap +import kotlin.collections.MutableMap +import kotlin.collections.get +import kotlin.collections.set +import kotlin.collections.toTypedArray import java.util.Date object Serializer { @JvmStatic - val gsonBuilder: GsonBuilder = GsonBuilder() + var gsonBuilder = GsonFireBuilder() + .createGsonBuilder() .registerTypeAdapter(Date::class.java, DateAdapter()) .registerTypeAdapter(OffsetDateTime::class.java, OffsetDateTimeAdapter()) .registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter()) .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) .registerTypeAdapter(ByteArray::class.java, ByteArrayAdapter()) - + @JvmStatic val gson: Gson by lazy { gsonBuilder.create() } + + fun getDiscriminatorValue(readElement: JsonElement, discriminatorField: String?): String? { + val element: JsonElement = readElement.getAsJsonObject().get(discriminatorField) + ?: throw IllegalArgumentException("missing discriminator field: <$discriminatorField>") + return element.getAsString() + } + + fun getClassByDiscriminator( + classByDiscriminatorValue: Map<*, *>, + discriminatorValue: String? + ): Class<*>? { + return classByDiscriminatorValue[discriminatorValue?.toUpperCase()] as Class<*>? + ?: throw IllegalArgumentException("cannot determine model class of name: <$discriminatorValue>") + } }