From 89bf9199b275bc5aca9c5c590739799aa43e3411 Mon Sep 17 00:00:00 2001 From: James Lucas Date: Thu, 16 Nov 2023 15:29:11 -0600 Subject: [PATCH] Fix errors in Kotlin unit methods Kotlin API fails on methods that don't return anything (which currently just includes `delete` methods) because the generated code by default tries to serialize the methods' return types in all cases, even if the return type is `Unit`. I'm not exactly sure whether this is properly a bug in the openapi generator or in moshi. In any case, I was unable to fix the error by doing what initially seemed most sensible, which was to register a moshi adapter for the `Unit` type. The fix here is not terribly elegant but in practice seems to fix the issue. I will also see about opening/adding to an existing issue on the openapi generator's github page and/or submitting a PR to fix this upstream. Note also that I've removed the `Serializer.kt` template, which is unused. We've already got an actual `Serializer` class stored in the generated code folder, so there's no reason to have the template. Fixes #1117. --- .../lib/src/test/com/svix/kotlin/BasicTest.kt | 1 + .../infrastructure/Serializer.kt.mustache | 116 ------------------ .../infrastructure/ApiClient.kt.mustache | 15 ++- 3 files changed, 13 insertions(+), 119 deletions(-) delete mode 100644 kotlin/templates/jvm-common/infrastructure/Serializer.kt.mustache diff --git a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt index b763b8ee3..a514fb2d1 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt @@ -24,6 +24,7 @@ class BasicTest { ) ) ) + svix.application.delete(applicationOut.id) } } diff --git a/kotlin/templates/jvm-common/infrastructure/Serializer.kt.mustache b/kotlin/templates/jvm-common/infrastructure/Serializer.kt.mustache deleted file mode 100644 index 31b83578e..000000000 --- a/kotlin/templates/jvm-common/infrastructure/Serializer.kt.mustache +++ /dev/null @@ -1,116 +0,0 @@ -package {{packageName}}.infrastructure - -{{#moshi}} -import com.squareup.moshi.Moshi -{{^moshiCodeGen}} -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory -{{/moshiCodeGen}} -{{/moshi}} -{{#gson}} -import com.google.gson.Gson -import com.google.gson.GsonBuilder -{{^threetenbp}} -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.OffsetDateTime -{{/threetenbp}} -{{#threetenbp}} -import org.threeten.bp.LocalDate -import org.threeten.bp.LocalDateTime -import org.threeten.bp.OffsetDateTime -{{/threetenbp}} -import java.util.UUID -{{/gson}} -{{#jackson}} -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.SerializationFeature -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -{{/jackson}} -import java.util.Date -{{#kotlinx_serialization}} -import java.math.BigDecimal -import java.math.BigInteger -{{^threetenbp}} -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.OffsetDateTime -{{/threetenbp}} -{{#threetenbp}} -import org.threeten.bp.LocalDate -import org.threeten.bp.LocalDateTime -import org.threeten.bp.OffsetDateTime -{{/threetenbp}} -import java.util.UUID -import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule -import java.net.URI -import java.net.URL -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicInteger -import java.util.concurrent.atomic.AtomicLong -{{/kotlinx_serialization}} - -{{#nonPublicApi}}internal {{/nonPublicApi}}object Serializer { -{{#moshi}} - @JvmStatic - val moshiBuilder: Moshi.Builder = Moshi.Builder() - .add(OffsetDateTimeAdapter()) - .add(LocalDateTimeAdapter()) - .add(LocalDateAdapter()) - .add(UUIDAdapter()) - .add(ByteArrayAdapter()) - .add(URIAdapter()) - {{^moshiCodeGen}} - .add(KotlinJsonAdapterFactory()) - {{/moshiCodeGen}} - .add(BigDecimalAdapter()) - .add(BigIntegerAdapter()) - - @JvmStatic - val moshi: Moshi by lazy { - moshiBuilder.build() - } -{{/moshi}} -{{#gson}} - @JvmStatic - val gsonBuilder: GsonBuilder = GsonBuilder() - .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() - } -{{/gson}} -{{#jackson}} - @JvmStatic - val jacksonObjectMapper: ObjectMapper = jacksonObjectMapper() - .findAndRegisterModules() - .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) - .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) -{{/jackson}} -{{#kotlinx_serialization}} - @JvmStatic - val kotlinSerializationAdapters = SerializersModule { - contextual(BigDecimal::class, BigDecimalAdapter) - contextual(BigInteger::class, BigIntegerAdapter) - contextual(Date::class, DateAdapter) - contextual(LocalDate::class, LocalDateAdapter) - contextual(LocalDateTime::class, LocalDateTimeAdapter) - contextual(OffsetDateTime::class, OffsetDateTimeAdapter) - contextual(UUID::class, UUIDAdapter) - contextual(AtomicInteger::class, AtomicIntegerAdapter) - contextual(AtomicLong::class, AtomicLongAdapter) - contextual(AtomicBoolean::class, AtomicBooleanAdapter) - contextual(URI::class, URIAdapter) - contextual(URL::class, URLAdapter) - contextual(StringBuilder::class, StringBuilderAdapter) - } - - @JvmStatic - val jvmJson: Json by lazy { Json { serializersModule = kotlinSerializationAdapters } } -{{/kotlinx_serialization}} -} diff --git a/kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache b/kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache index dabdc7e97..537805be2 100644 --- a/kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache +++ b/kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache @@ -171,9 +171,18 @@ import kotlin.random.Random ) {{/jvm-okhttp3}} {{#jvm-okhttp4}} - mediaType == JsonMediaType -> {{#moshi}}Serializer.moshi.adapter(T::class.java).toJson(content){{/moshi}}{{#gson}}Serializer.gson.toJson(content, T::class.java){{/gson}}{{#jackson}}Serializer.jacksonObjectMapper.writeValueAsString(content){{/jackson}}{{#kotlinx_serialization}}Serializer.jvmJson.encodeToString(content){{/kotlinx_serialization}}.toRequestBody( - mediaType.toMediaTypeOrNull() - ) + mediaType == JsonMediaType -> { + // This is a bit of a hack to avoid moshi + // failing on trying to call `toJson` on + // a Unit type: + if (T::class.java == Unit::class.java) { + ByteArray(0).toRequestBody() + } else { + {{#moshi}}Serializer.moshi.adapter(T::class.java).toJson(content){{/moshi}}{{#gson}}Serializer.gson.toJson(content, T::class.java){{/gson}}{{#jackson}}Serializer.jacksonObjectMapper.writeValueAsString(content){{/jackson}}{{#kotlinx_serialization}}Serializer.jvmJson.encodeToString(content){{/kotlinx_serialization}}.toRequestBody( + mediaType.toMediaTypeOrNull() + ) + } + } {{/jvm-okhttp4}} mediaType == XmlMediaType -> throw UnsupportedOperationException("xml not currently supported.") // TODO: this should be extended with other serializers