-
-
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
Nested type arguments doesn't work with polymorphic types #1604
Comments
And this is with late(st) version, like 2.8.8? |
This is with 2.8.8 |
I am able to recreate this bug without using polymorphism. Using the following code, the GoodOuter can be serialized correctly, but BadOuter fails. I've tested this with both 2.8.4 and 2.8.10.
|
@wlp1979 Thank you for sharing. |
Yes, I can reproduce this. Looks like code path may be slightly different, but at least there's something to dig into. |
@cowtowncoder I isolated this down to a change introduced in 2.7.4. Serialization of both of these object graphs succeeds starting back as far as 2.5.3 and works through 2.7.3. I'll look at the changes to databind in 2.7.4 to see if there's something obvious. I'm a long-time Jackson user, but have never had cause to modify the codebase, so it may take me a bit ;) |
Scanning through the diff, this looks fishy:
|
@epollan Excellent detective work. This is bit concerning, mostly since I do not think that undoing change would work here. Code would rather have to do better resolution of type parameterization, ideally "pushing" type variables through hierarchy and get binding that way. But it does make sense that this would cause false match of bindings. |
Yes, I think what goes wrong here is resolution of
with sub-type of
which short-circuits with assumption that matching number of type variables means that simple substitution works; not true in this case. Proper resolution would resolve original type, retaining type variable, and then sort of back-tracking... This may be very difficult to solve, esp. for 2.9.x (I won't even attempt changing any older versions since risks for change will be non-trivial) |
And this essentially goes wrong in the fallback case, in which subtype (one being specialized as) is given existing Removing handling and only using base type as-is would fix this case, but breaks one of existing tests (#1186), in which (conversely) existing handling works ok. |
Looks like the problem is in |
@cowtowncoder is there a README/doc that describes how to get the jackson code compiling locally? The tip of master references a parent pom of
I pinned the parent to the latest released version I found on maven central (2.9.2). I then get an error from the enforcer plugin complaining about jacoco:
I pinned jacoco to
I suspect there's some basic local config I need to do to get the jackson-xxx modules building locally... |
@epollan I would recommend using branch |
I checked out the 2.9.2 tag & it builds fine now. That type binding transfer to the subclass that's at issue here is pretty concerning... I can see how it would help immensely for retaining type parameterization data for collection/map values, but it's so easy for it to do the wrong thing... Question: what's the implication of the fall-through case (i.e. I'm wondering if maybe specializing this branch to just apply to collection/map would work? |
As I suspected, restricting that branch of type binding transfer to just collection-like types causes tests to fail:
I think what actually needs to happen is to "unwind" the base type's type bindings in this situation. E.g., given |
blargh. search space is large. I'm just now appreciating that the type parameterization info available on |
Actually I know what the problem is and how to approach it -- did it for But the approach that would work really is to resolve the subtype (class), but keeping context of resolved super-type (base type), and once resolution hits unbound parent type of same type-erased type, bind it. For example: we have Does this make more sense? Challenge within For what it is worth, Classmate: https://github.com/FasterXML/java-classmate has functionality for this. Whether having a look at it helps or not I don't know; APIs are quite different since Jackson adds more usage-specific semantics (f.ex. |
Yes -- verifying that My plan is to code up a guard against the type binding transfer for exactly this case (albeit simplified for the arity-1 type binding case) and see what tests break. TBH, I think we're going to end up changing our code to avoid the problem. But, I kind of want to dig a little deeper in case there's a reasonable way out of this. At the very least, I'll have greater understanding of the bug and where it might bite me in the future. |
Yes. So, just to clarify what I meant: existing type resolution works fine, as is, when only resolving a single type. What is needed here is sort of re-parent things (grafting?), and it could either be implemented as separate recursive process (instead of resolving it is actually walking existing type hierarchy, really), or trying to retrofit resolution with this. There are further challenges in that type objects are (mostly, ideally should be fully) immutable, to figure out what and how to copy. |
The naive fix for the arity 1 type parameterization case works and all the databind tests pass. The
with
Now, whether this can be generalized to arity N type parameterization in a reasonable manner remains to be seen. |
Brave attempt, but I am almost certain that this will lose type information since it drops anything that base type had, and since subtype is type erased this can not be brought back from anywhere. Still, something along these lines could work. I hope to find time to work a bit on this, since discussion has helped me remember where I left off after 2.7 (and leaving this one known area of concern -- literally the only known gap at this point, wrt type resolution). |
I think I have it generalized. Will clone, branch, and PR tomorrow after cleaning up what I have. I'm not sure familiar with how the |
Ok. With enough banging my head against the wall, and then going to |
Hi, I was able to track this back to your change in this issue. I've isolated the problem to a simple maven based project, you can find it here: https://github.com/dnno/jackson-serialization-problem/ The classes we try to serialize make use of generics and Jackson now isn't able to handle them anymore. Type resolution stops here: TypeFactory._verifyAndResolvePlaceholders():476
I don't really understand a lot of what's happening here, but what I do see is, that if I manually set the resulting error String to , the serialization will work fine. Could it be, that it's wrong to just compare for the same raw classes, but instead traverse the type hierarchy? In my case it's comparing a List (actual) to an Object (expected). A successful comparison would make sense for me. It would be great if you could take a look at our case, let me know if I can provide further information. |
@dnno Could you please file a new issue for this: even if the problem is related to this one (caused by fix), it is easier to track fix that way. You can add a reference to this issue as likely root cause. I can't say much except that this could be related to / same as #1964, which will be fixed for |
When using @JsonSubTypes/@JsonTypeInfo on an interface with a generic parameter (de)serialising a subclass that wraps it's own generic parameter in another generic class or interface doesn't work.
It's a bit complex to explain with words so here's a short example:
This crashes with the following exception:
If I try work around it by making
value
into aList<T>
deserialisation works but serialisation gives me aList<String>
instead ofList<UUID>
so using a list afterperform
will throwClassCastException
s.The text was updated successfully, but these errors were encountered: