-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Serialising generic value classes via Reference Types (like Optional) fails to include type information #1673
Comments
I am not sure I know what "templated" class here means. |
@cowtowncoder I meant any generic class or interface that is parameterized over types. More specifically, my problem occurs on instances of classes/interfaces whos GenericType is abstract |
@pwhissell Ok. I guess I am not quite sure what is being asked then. If this is about ability to handle nested generic type information, answer is likely "no, this goes beyond what Jackson can do". Example itself seems something that should already work, so I am probably missing something: |
Given the example
When I serialize this list,
then the type information concerning ItemADto and ItemBDto are not serialized and therefor lost.
Since AbstractItemDto specifies the usage of a "type" attribute for JsonTypeInfo I would expect the serialized string to contain the "type" attribute necessary for the list's deserialization
this would allow me to effectively deserialise itemsJson into a list containing one instance of ItemADto and one instance of ItemBDto |
@pwhissell Ah. No, it's not because this is not supported, but due to Java Type Erasure. This is a FAQ. My main suggestion is really to avoid ever using generic types as root value (that is, value directly passed to ObjectMapper/ObjectWriter). They are fine everywhere else, when reached via property, since generic signature is actually retained in class definition, and thereby accessible. Instead, either:
But if you really really want to use mapper.writerFor(new TypeReference<List<AbstractDTO.>>() { })
.writeValueAsBytes(value); As things are, there may be issues here too, unfortunately, as this forces type for serializer to use |
@cowtowncoder thank you for your detailed answer.
Because of type erasure, the code rather looks something like this after compilation:
This is why there is no way to use reflection with
That being said, the instance of the property which's type is parameterized (in my case
This is true for any generic class including
All that being said, would it be possible for jackson to implement such logic in a future version? |
@pwhissell Jackson does indeed resolve any and all generic type information that is retained by field, method, super-type declarations. But this is not where the problem occurs: rather, your |
@cowtowncoder I hadn't realized how the problem only occurs in lists and other iterables, this actually fixes half of my problem. What are the reasons for which the polymorphic type handler is only defined once for |
@pwhissell It's due to multiple reasons, including performance but not as the main reason. Come to think of this through again, I think a real show-stopper would be that there really is no way to reliably figure out polymorphic type handling ( So I am actually not sure how polymorphic deserialization could be implemented on per-element basis without mandating either additional metadata, or limitation on kinds of type ids that were allowed for |
@cowtowncoder You are absolutely right with a JSON string there is no way of knowing what Type is represented by the JSON object. However is limitation stil applies when polymorphism isn't in play. I'm not sure what the implementation is but deserializing already works with jackson out of the box for example, if I wrap my earlier polymorphic list in a Foo class like so
and I force the definition of the type attribute in my earlier classes like so in order to work around the serialisation problem:
then deserialization with jackson works out of the box:
As for Lists that aren't wrapped in an object, we could use jackson's overloaded implementation of objMapper.readValue and specify a type argument for the destination class like so:
|
I am not sure why you think this is against what I am saying -- your root value is NOT generic type. And specifying type does work as you suggested as long as you use it ALSO for serialization -- this is where base type comes into play. Deserialization side is fine.
|
Does it matter how many levels it goes down? For example, if a non generic type has a field that is an AtomicReference to a List of a polymorphic type. Currently that case does not work with 2.9 (FasterXML/jackson-module-scala#346 (comment)). |
@brharrington Hmmh. I can not actually answer that definitely: nesting of types would work fine for, say, parameterized elements of a I think I'd need to see specific case, with Java reproduction. Scala module, further, has its own issues that could be problematic. |
See this test case: brharrington@1549473 |
Thanks. |
I can see the failure and yes, looks like it is missing type information it should include. |
Ok that took a while from beginning to end: thank you for your patience. In the end it makes sense; one piece in elaborate dance was missing from |
thanks guys, I havent had the chance to try the implementation but you juste made my day :) |
Thank you for your work on this! Very happy to see the jackson-module-scala issue unblocked. |
:) I hope patch to Scala module to base |
Fixes FasterXML#346. Note this also update the jackson version to 2.9.4 as it has a fix that is needed to avoid breaking other tests. See FasterXML/jackson-databind#1673 for more details.
After going through a couple issues, I came to understand that Jackson always uses declared type of value to figure out whether to include type information. This is done to ensure that type settings are identical between serialization and deserialization.
However isn't that statement false for templated class?. This robustness would be better ensured if the type id settings would be bound to declared types for all untemplated classes but were bound to both declaration and component classes for templated classes. This would imply obtaining the type information at runtime, thus serialisation/deserialisation of templated classes would be a little bit less efficient but that drawback would be negligeable at least in my case.
This would allow for serialisation/deserialisation of Templated classes who's component class are abstract ex. List
The text was updated successfully, but these errors were encountered: