-
Notifications
You must be signed in to change notification settings - Fork 620
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
@JsonClassDiscriminator
should work on interfaces
#2181
Comments
Thanks for this detailed write-up! You've mentioned several problems here:
So, there are several existing ways to introspect the module: Another option (which we usually forget about) is to use
It is a bit clumsy to use, but with Regarding points 1 and 2: They're mostly connected with the fact that non-sealed interfaces are serializable automatically and do not have any generated code on their own — a polymorphic serializer is always inserted in the place where we meet them. It seemed a good design decision at that time; however, maybe it is time to reconsider it. |
Thanks for such a detailed answer. Indeed, making On another hand, I had totally overlooked Regarding points 1 and 2, I agree it'd be useful generating code for interfaces, if it'd allow replacing the default polymorphic serializer without trickery. The use of
|
What is your use-case and why do you need this feature?
I want to use polymorphic deserialization with an interface as the root class, using a different class discriminator from
"type"
, but changing theclassDiscriminator
setting globally is limiting and undesirable.Describe the solution you'd like
The
@JsonClassDiscriminator
annotation should not be ignored on interfaces.Note that annotating each subclass with
@JsonClassDiscriminator
still doesn't help.Workaround
It's possible to create a custom serializer which properly recognizes the
@JsonClassDiscriminator
annotation on interfaces, and then use it withcontextual
in the module descriptor, as long as the interface is annotated with@Serializable(with = KSerializer::class)
. Using this approach, it's even possible to support non-string discriminators (Add support for numeric json class discriminators #2142), by using custom annotations (e.g.,@IntTypeDiscriminator
), as well as multiple nested type discriminators in the same hierarchy (see the example).Example workaround
However, this requires the custom serializer to access the
polyBase2Serializers
property from theSerializersModule
(which is not part of the public API), or use a custom module descriptor that wrapsSerializersModule
exposing the polymorphic hierarchy information (which also requires wrapping theJson
format, so its custom module descriptor is accessible from a global identity map (at least this approach does not rely on internal API)).Furthermore, the
contextual
setting in theSerializersModule
for the interface is only used if the interface itself is annotated with@Serializable
, but, since interfaces cannot be annotated with@Serializable
without awith
argument (because it's a compile error to clarify intent), it's necessary to annotate the interface with@Serializable(with = KSerializer::class)
, as any other argument will result in a compiler warning (a serializer ofAny
is not applicable to an interface type).I imagine that the use of
@Serializable(with = KSerializer::class)
is unintended and probably an overlook of the compile error that prevents using@Serializable
without arguments on interfaces, but it's the cleanest way I've found to get the interface to be deserialized with the serializer specified ascontextual
in the module descriptor. Note that using@Serializable(with = DiscriminatedPolymorphicSerializer::class)
not only produces a compiler warning, but it's both pointless and wrong, since the passed serializer class should have a constructor accepting type argument serializers, if anything, which is not the case of the serializer in this example.As shown, this workaround is actually even more powerful than the requested feature. It'd be nice if
@Polymorphic
types could be configured with a different serializer than the built-inPolymorphicSerializer
(e.g. a structure-based serializer).Additional thoughts
I'd like to propose exposing the
polyBase2Serializers
map (indirectly) with a function onSerializersModule
to retrieve the (immutable) map from subclasses of a given class to their serializers, so at least this workaround wouldn't be as sketchy as it currently is.This function could be an overload of the already existing
getPolymorphic
functions, that wouldn't require an instance or the serial name of a subclass:It'd also be ideal if the
polyBase2DefaultDeserializerProvider
map was somehow accessible. Why isn't all theSerializersModule
information public anyways? It's incredibly frustrating to develop custom serializers that reuse module configuration.Additionally, the idea of a custom module descriptor would at least be easier to implement if the
Json
format (and others) could be configured with custom settings (e.g., stored in a map by settings class).This could be pretty useful to allow custom serializers to use format-specific configuration.
Finally, if supporting
@JsonClassDiscriminator
for interfaces is not possible, then at least the annotation should be reported as an error when applied to an interface, since this behavior is unexpected (even if the annotation containsClass
in its name).The text was updated successfully, but these errors were encountered: