Skip to content

JsonContentPolymorphicSerializer should provide a non-final selectSerializer #2622

Open
@bcmedeiros

Description

@bcmedeiros

What is your use-case and why do you need this feature?

JsonContentPolymorphicSerializer is a very useful abstract class and I have used it quite a few times, but now I have a slightly different problem that cannot be fixed using it.

I'm basically trying to support serialization on a Map<String, Any> where Any could be String or a a few classes that belong to a polymorphic hierarchy. (That would be a perfect case for a String | MyObject union type, but we don't have that yet).

This is how I implemented it:

class TemplateVariablesSerializer: JsonContentPolymorphicSerializer<Any>(Any::class) {
    override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Any> {
        return when (element) {
            is JsonArray -> throw IllegalStateException("arrays are not supported yet")
            is JsonObject -> serializer<MySealedHierarchy>()
            is JsonPrimitive -> when {
                element.isString -> serializer<String>()
                else -> throw IllegalStateException("non-string primitive types are not supported yet")
            }
        }
    }
}

Everything works great for deserialization if I have the correct payload, but for serialization we end up with a payload without the discriminator value as the serializer of the instance is used instead of the MySealedHierarchy one.

Describe the solution you'd like

If we had something like

protected fun selectSerializer(encoder: Encoder, value: T): SerializationStrategy<T> {
    encoder.serializersModule.getPolymorphic(baseClass, value)
                    ?: value::class.serializerOrNull()
                    ?: throwSubtypeNotRegistered(value::class, baseClass)
}

we could actually override the default serializer to consider the value type:

override fun selectSerializer(encoder: Encoder, value: T): SerializationStrategy<T> {
    when (value) {
        is MySealedHierarchy -> serializer<MySealedHierarchy>()
        else -> super.selectSerializer(encoder, value)
    }
}

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