diff --git a/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/common/src/io/ktor/serialization/kotlinx/SerializerLookup.kt b/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/common/src/io/ktor/serialization/kotlinx/SerializerLookup.kt index d33f4320f4a..76204681050 100644 --- a/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/common/src/io/ktor/serialization/kotlinx/SerializerLookup.kt +++ b/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/common/src/io/ktor/serialization/kotlinx/SerializerLookup.kt @@ -14,8 +14,13 @@ internal fun serializerFromTypeInfo( typeInfo: TypeInfo, module: SerializersModule ): KSerializer<*> { - return module.getContextual(typeInfo.type) - ?: typeInfo.kotlinType?.let { module.serializerOrNull(it) } + return typeInfo.kotlinType + ?.let { type -> + if (type.arguments.isEmpty()) null // fallback to simple case because of + // https://github.com/Kotlin/kotlinx.serialization/issues/1870 + else module.serializerOrNull(type) + } + ?: module.getContextual(typeInfo.type) ?: typeInfo.type.serializer() } diff --git a/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/ktor-serialization-kotlinx-json/common/test/JsonSerializationTest.kt b/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/ktor-serialization-kotlinx-json/common/test/JsonSerializationTest.kt index 0d119b72567..36b68dec97b 100644 --- a/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/ktor-serialization-kotlinx-json/common/test/JsonSerializationTest.kt +++ b/ktor-shared/ktor-serialization/ktor-serialization-kotlinx/ktor-serialization-kotlinx-json/common/test/JsonSerializationTest.kt @@ -8,8 +8,16 @@ import io.ktor.serialization.kotlinx.* import io.ktor.serialization.kotlinx.json.* import io.ktor.serialization.kotlinx.test.* import io.ktor.test.dispatcher.* +import io.ktor.util.reflect.* +import io.ktor.utils.io.* +import io.ktor.utils.io.charsets.* +import io.ktor.utils.io.core.* import kotlinx.serialization.* +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.encoding.* import kotlinx.serialization.json.* +import kotlinx.serialization.modules.* +import kotlin.reflect.* import kotlin.test.* @OptIn(ExperimentalSerializationApi::class) @@ -54,4 +62,91 @@ class JsonSerializationTest : AbstractSerializationTest() { assertEquals("""{"a":"1","b":["c",2]}""", result.decodeToString()) } } + + @Test + fun testContextual() = testSuspend { + val serializer = KotlinxSerializationConverter( + Json { + prettyPrint = true + encodeDefaults = true + serializersModule = + SerializersModule { + contextual(Either::class) { serializers: List> -> + EitherSerializer(serializers[0], serializers[1]) + } + } + } + ) + val dogJson = """{"age": 8,"name":"Auri"}""" + assertEquals( + Either.Right(DogDTO(8, "Auri")), + serializer.deserialize( + Charsets.UTF_8, + typeInfo>(), + ByteReadChannel(dogJson.toByteArray()) + ) + ) + val errorJson = """{"message": "Some error"}""" + assertEquals( + Either.Left(ErrorDTO("Some error")), + serializer.deserialize( + Charsets.UTF_8, + typeInfo>(), + ByteReadChannel(errorJson.toByteArray()) + ) + ) + + val emptyErrorJson = "{}" + assertEquals( + Either.Left(ErrorDTO("Some default error")), + serializer.deserialize( + Charsets.UTF_8, + typeInfo>(), + ByteReadChannel(emptyErrorJson.toByteArray()) + ) + ) + } +} + +@Serializable +data class DogDTO(val age: Int, val name: String) + +@Serializable +data class ErrorDTO(val message: String = "Some default error") + +sealed class Either { + + data class Left(val left: L) : Either() + + data class Right(val right: R) : Either() +} + +class EitherSerializer( + private val leftSerializer: KSerializer, + private val rightSerializer: KSerializer, +) : KSerializer> { + + override val descriptor: SerialDescriptor = + buildClassSerialDescriptor("NetworkEitherSerializer") { + element("left", leftSerializer.descriptor) + element("right", rightSerializer.descriptor) + } + + override fun deserialize(decoder: Decoder): Either { + require(decoder is JsonDecoder) { "only works in JSON format" } + val element: JsonElement = decoder.decodeJsonElement() + + return try { + Either.Right(decoder.json.decodeFromJsonElement(rightSerializer, element)) + } catch (throwable: Throwable) { + Either.Left(decoder.json.decodeFromJsonElement(leftSerializer, element)) + } + } + + override fun serialize(encoder: Encoder, value: Either) { + when (value) { + is Either.Left -> encoder.encodeSerializableValue(leftSerializer, value.left) + is Either.Right -> encoder.encodeSerializableValue(rightSerializer, value.right) + } + } } diff --git a/ktor-utils/jvm/src/io/ktor/util/debug/IntellijIdeaDebugDetectorJvm.kt b/ktor-utils/jvm/src/io/ktor/util/debug/IntellijIdeaDebugDetectorJvm.kt index 3dd0dbd0b60..13e668d6e20 100644 --- a/ktor-utils/jvm/src/io/ktor/util/debug/IntellijIdeaDebugDetectorJvm.kt +++ b/ktor-utils/jvm/src/io/ktor/util/debug/IntellijIdeaDebugDetectorJvm.kt @@ -5,7 +5,6 @@ package io.ktor.util.debug -import java.lang.ClassNotFoundException import java.lang.management.* internal actual object IntellijIdeaDebugDetector {