-
-
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
Deserialization failure with Polymorphism using JsonTypeInfo defaultImpl
, subtype as target
#1565
Comments
@j1234d2003 It is not possible to know which version would behave differently before understand specific issue. And although explanation may be helpful, what really helps is a reproduction, ideally simple unit test. But also make sure you follow the logic of I suspect this could be related to #1358. |
Thank you for your response. I agree unit testing on older version is vital and would start by 2.7.9. For longer term solution, I would like to ensure I understand the logic of defaultImpl resolution explained in your response and reflect further based on the polymorphic usage I have seen over the years. I also studied issues 1358 and 1339 to improve my understanding of the problem. In my example:
So based on your description, it seems like you are stating
It should be okay to fail if the encoded value DID NOT contain the id property and you try to decode the value as a If a defaultImpl class can never be extended, this is truly troublesome in many real-world usecases. Having a Java interface and a class hierarchy that implements this hierarchy is fairly common. For many usecases such as in messaging protocols, it is necessary to have a default format if format is not explicitly specified. Now the selection of default format is typically based on the domain semantics and not class hierarchy structure. Therefore, a requirement that the defaultImpl class must always be at bottom (away from root - as a leaf) of class hierarchy is impractical in many cases. Even if it is designed with such constraint, a future refactoring that requires extending that defaultImpl class can break the software. It many cases, the software has knowledge of actual target type using means outside the decoders (e.g. message headers) and therefore, it is reasonable to expect that a decoding attempt would be performed with the exact expected type - not the defaultImpl type - we don't want a leakage of an undesirable restriction into software due to usage of Jackson decoding library. E.g. Consider a Shape interface annotated using It would seem that the correct behavior should be that you cannot expect to get a Please share your thoughts. |
Sorry, I accidentally closed it. |
I wish I had more to spend here, but from glance I think #1358 would be along lines you are thinking. There is also the question of whether attempt to direct deserialization into subtype ( In the meantime, in practical terms, I do not think behavior here will be changed in patch releases: so the first version where usage would work as desired is 2.9. |
Thank you for your detailed response. In order to perform a thorough analysis of current behavior and find an older version that would allow me to proceed in the short term, here is a sample test program using the Shape class hierarchy: For version 2.8.7, here are the results: As is apparent from this result, a new problem has been detected that is related to defaultImpl: This problem seems more troubling as I cannot comprehend a workaround like the explicit case you proposed. It is would be unreasonable to restrict use of concrete types in other domain-specific classes as only members with those concrete types may make sense for those domain-specific classes. As before, the problem with top-most object type persists as follows: Using the actual concrete type for deserialization is a valid usecase as in most of our target usecases, it is necessary to know the type of content you are expecting - like when you are processing a message, you already have message type from a previously decoded message header (may be other format) and now you are decoding the message payload to get additional information to process this message. It would be best if we did not have to use the Interface type or some super-type due to deserialization library constraints as you already know what you need. Getting something other than that may be an error. One can also look at this problem in another way: The type id resolver is able to completely resolve the type from the encoded data and therefore it should be allowed to do so. It seems reasonable to depend on defaultImpl when type could not be detected from the encoded data and therefore there is no further recourse to determine how to proceed w.r.t. type detection. If defaultImpl is not meant to work like this, it would be desirable to provide something which does offer this functionality. It seems overly restrictive for a deserialization library to constraint the type of expected data or data-type of domain-specific classes. It would help if a deserializer throws an exception only when the underlying encoded data cannot be decoded to what the user requested. Right now it throws an exception even when the encoded data is correct. The same tests for 2.7.9 (with few mods for TypeIdResolver impl) did not fail for any of the above usecases. Here is the result for 2.7.9 testing: So I plan to move to 2.7.9 in short term but hope you can help fix this issue so that I can proceed to the latest version in the near future. Hope you will be able to address both of these problem usecases. You hinted on 2.9 version. Do you have an estimated release time-frame for stable version for 2.9? |
- Avoids using a default implementation when the defaultImpl anntotation should not apply.
- Checks for multiple base classes annotated with @JsonTypeInfo(defaultImpl=...)
defaultImpl
, subtype as target
Issue verified on version jackson-databind 2.8.7 on Ubuntu 14.04, Java 1.8.0_25. A sample code
CTestTypeId.java.txt
demonstrates this bug.
A class hierarchy that implements an interface annotated with a @JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="typeInfo", defaultImpl=CBaseClass.class) and a @JsonTypeIdResolve fails to deserialize a derived class that extends the defaultImpl CBaseClass with exception IllegalArgumentException stating that the defaultImpl class is not a subtype of the extending derived class thrown at com.fasterxml.jackson.databind.type.TypeFactory.constructSpecializedType(TypeFactory.java:359)
Consider interface CTestInterface annotated with
@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="typeInfo", defaultImpl=CBaseClass.class) and
@JsonTypeIdResolver(CTypeMapper.class)
Consider two classes:
On attempt to deserialize data for a CDerivedClass using an ObjectMapper, the type-deserializer failed to be built as demonstrated by the following stack trace. Note that an instance of CBaseClass gets deserialized correctly. For my target usecase, data does not always include the "typeInfo" property and hence defaultImpl use becomes necessary.
Exception in thread "main" java.lang.IllegalArgumentException: Class com.example.CTestTypeId$CBaseClass not subtype of [simple type, class com.example.CTestTypeId$CDerivedClass]
at com.fasterxml.jackson.databind.type.TypeFactory.constructSpecializedType(TypeFactory.java:359)
at com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder.buildTypeDeserializer(StdTypeResolverBuilder.java:128)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findTypeDeserializer(BasicDeserializerFactory.java:1373)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:482)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3899)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3794)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842)
at com.example.CTestTypeId.main(CTestTypeId.java:177)
I am trying to migrate from jackson-databind 2.1.2 to a more recent production version. Is it possible to know a version that does not suffer from this bug as I need to migrate to a stable version very quickly.
The text was updated successfully, but these errors were encountered: