-
Notifications
You must be signed in to change notification settings - Fork 660
Description
Describe the bug
Using contextual serialization and encoding functions with reified type parameters doesn't work for generic interfaces. It works if I pass a serializer manually or change the interface to an abstract class.
To Reproduce
Attach a code snippet or test data if possible.
Code:
@Serializable(with = OptionSerializer::class)
/*sealed*/ interface Option<out T>
class Some<out T>(val value: T) : Option<T>
object None : Option<Nothing>
@Serializable
class OptionSurrogate<out T>(val isPresent: Boolean, val value: T?)
fun <T> Option<T>.toSurrogate() =
when (this) {
is Some<T> -> OptionSurrogate(true, value)
is None -> OptionSurrogate(false, null)
else -> throw IllegalArgumentException()
}
fun <T> OptionSurrogate<T>.toOption() =
if (isPresent) Some(value!!)
else None
class OptionSerializer<T>(valueSerializer: KSerializer<T>) : KSerializer<Option<T>> {
val surrogateSerializer = OptionSurrogate.serializer(valueSerializer)
override val descriptor: SerialDescriptor
get() = surrogateSerializer.descriptor
override fun serialize(encoder: Encoder, value: Option<T>) =
encoder.encodeSerializableValue(surrogateSerializer, value.toSurrogate())
override fun deserialize(decoder: Decoder): Option<T> =
decoder.decodeSerializableValue(surrogateSerializer).toOption()
}
class Dummy
@Serializer(forClass = Dummy::class)
object DummySerializer
fun main() {
val format0 = Json {
serializersModule = SerializersModule {
}
}
try {
println(format0.encodeToString<Option<Dummy>>(Some(Dummy())))
} catch (e: Exception) {
e.printStackTrace()
}
val format1 = Json {
serializersModule = SerializersModule {
contextual(DummySerializer)
}
}
try {
println(format1.encodeToString<Option<Dummy>>(Some(Dummy())))
} catch (e: Exception) {
e.printStackTrace()
}
println(Json.encodeToString(OptionSerializer(DummySerializer), Some(Dummy())))
}
Output:
kotlinx.serialization.SerializationException: Serializer for class 'Dummy' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
at kotlinx.serialization.internal.PlatformKt.platformSpecificSerializerNotRegistered(Platform.kt:29)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:60)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
at kotlinx.serialization.SerializersKt__SerializersKt.builtinSerializer$SerializersKt__SerializersKt(Serializers.kt:96)
at kotlinx.serialization.SerializersKt__SerializersKt.serializerByKTypeImpl$SerializersKt__SerializersKt(Serializers.kt:84)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:59)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
at OptionKotlinxSerializationTestKt.main(OptionKotlinxSerializationTest.kt:118)
at OptionKotlinxSerializationTestKt.main(OptionKotlinxSerializationTest.kt)
kotlinx.serialization.SerializationException: Serializer for class 'Option' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
at kotlinx.serialization.internal.PlatformKt.platformSpecificSerializerNotRegistered(Platform.kt:29)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:60)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
at OptionKotlinxSerializationTestKt.main(OptionKotlinxSerializationTest.kt:121)
at OptionKotlinxSerializationTestKt.main(OptionKotlinxSerializationTest.kt)
{"isPresent":true,"value":{}}
As one can see, if I specify an empty SerializersModule
, I get "Serializer for class 'Dummy' is not found."; if I add DummySerializer
to it, I get "Serializer for class 'Option' is not found."; It works if I pass OptionSerializer(DummySerializer)
manually.
It works with no problem if I change the Option
interface to an open, abstract, or sealed class.
Expected behavior
{"isPresent":true,"value":{}}
should be printed for the second println
statement.
Environment
- Kotlin version: [1.5.21]
- Library version: [1.2.2]
- Kotlin platforms: [JVM]
- Gradle version: [7.1.1]
- IDE version (if bug is related to the IDE) [IntelliJ IDEA 2021.2 (Community Edition), Build #IC-212.4746.92, built on July 27, 2021]
- Other relevant context [OS version Windows 10, JRE version 11.0.11+9-b1504.13 amd64]