Skip to content

getPolymorphic won't get correct serializing strategy for classes with generic parameters #2258

@victorteokw

Description

@victorteokw

Describe the bug
Given a serializable class like this, serialize with a custom any serializer which is a bare serializer without deserializer. This is an input type, thus deserialization is not needed. When passing Int, Boolean, IntArray and custom serializable classes, it works all fine. This serializer won't work for array, list and map with generic arguments like K and V.

@Serializable
data class User(
    @Serializable(with=AnySerializer::class)
    val name: Any? = null,
    val age: Int
)

object AnySerializer : JsonContentPolymorphicSerializer<Any>(Any::class) {
    override fun selectDeserializer(content: JsonElement) = throw NotImplementedError()
}

The reason is that this method won't return a serializing strategy for the type with generic parameter.

    override fun <T : Any> getPolymorphic(baseClass: KClass<in T>, value: T): SerializationStrategy<T>? {
        if (!baseClass.isInstance(value)) return null
        // Registered
        val registered = polyBase2Serializers[baseClass]?.get(value::class) as? SerializationStrategy<T>
        if (registered != null) return registered
        // Default
        return (polyBase2DefaultSerializerProvider[baseClass] as? PolymorphicSerializerProvider<T>)?.invoke(value)
    }

To Reproduce
Create a file like this and run:

@Serializable
data class User(
    @Serializable(with=AnySerializer::class)
    val name: Any? = null,
    val age: Int
)

@Serializable
data class Post(
    @Serializable(with=AnySerializer::class)
    val name: Any?,
    val age: Int? = null,
)

@OptIn(ExperimentalSerializationApi::class)
val json_serializer = Json {
    explicitNulls = false
}

object AnySerializer : JsonContentPolymorphicSerializer<Any>(Any::class) {
    override fun selectDeserializer(content: JsonElement) = throw NotImplementedError()
}

fun main() {
    val json = json_serializer.encodeToString(Post(name=User(age=400, name= mapOf("a" to 1, "b" to 2)), age=NULL))
    println("json: $json")
}

Expected behavior
Expect to successfully encode the class with any fields into json string.

Environment

  • Kotlin version: 1.8.10
  • Library version: 1.5.0
  • Kotlin platforms: JVM
  • Gradle version: 7.4.2
  • IDE version: IntelliJ IDEA 2023.1 (Community Edition)
  • OS version: macOS 13.2
  • JVM version: 11

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions