Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonContentPolymorphicSerializer should provide a non-final selectSerializer #2622

Open
bcmedeiros opened this issue Apr 8, 2024 · 1 comment
Labels

Comments

@bcmedeiros
Copy link

bcmedeiros commented Apr 8, 2024

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)
    }
}
@bcmedeiros
Copy link
Author

#1247 might help with this one we have POLYMORPHIC_AND_SUBTYPES, but I think having an override-able selectSerializer is a good change anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant