Delegate serialization produces incorrect results on Collection elements with polymorphism
Describe the bug When using a custom serializer that is polymorphic on the type argument of a list, the serializer produces an array instead of the expected object
To Reproduce
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@Serializable
sealed interface Base
@Serializable
data class GenericError(@SerialName("error_code") val errorCode: Int) : Base
@Serializable
data class Works(val messages: List<Base>)
@Serializable
data class Broken(val messages: List<@Serializable(DelegateSerializer::class) Base>)
object DelegateSerializer : KSerializer<Base> by Base.serializer()
val format = Json { prettyPrint = true }
fun main() {
/**
* Produces:
* {
* "messages": [
* {
* "type": "my.app.GenericError",
* "error_code": 404
* }
* ]
* }
*/
println(format.encodeToString(Works(listOf(GenericError(404)))))
/**
* Produces:
* {
* "messages": [
* ["my.app.GenericError", {
* "error_code": 404
* }
* ]
* ]
* }
*/
println(format.encodeToString(Broken(listOf(GenericError(404)))))
}
Expected behavior
Both lines should produce the same output since the delegate serializer should be no-op in this case since everything should be delegated to the generated Base serializer
Environment
- Kotlin version: 1.9.10
- Library version: 1.6.0
- Kotlin platforms: JVM
This bug is connected to the fact that we use is AbstractPolymorphicSerializer check, which the delegate does not satisfy. I do not remember exactly why it is not a PolymorphicKind check, but changing this will have a big impact now.
Related to the #2460
Experiencing the same issue
What's the workaround for this?
EDIT: https://github.com/Kotlin/kotlinx-datetime/blob/master/core/common/src/serializers/DateTimeUnitSerializers.kt#L199
@SettingDust What happens is that for a custom polymorphic serializer (including a delegate) serialization the special treatment by json doesn't work, but rather uses the default behaviour (wrap in a container with type and value properties). As this behaviour is predictable and not incorrect any changes to this would need to be configurable.
The current implementation uses internals of AbstractPolymorphicSerializer rather than a special encoder that only would rely on behaviour (that could be implemented by other serializers). This is very possible, but needs changes in the library (and possibly a configuration flag)