-
Notifications
You must be signed in to change notification settings - Fork 118
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
Unannotated single-argument constructor / factory method not considered a creator #50
Comments
We now configure Lombok to explicitly add @ConstructorProperties annotations to generated constructors as Jackson otherwise doesn't deserialize value objects with single-argument constructors properly. Related ticket: FasterXML/jackson-modules-java8#50
One thing to verify: I assume you are doing this already but... is this against |
As described on |
Most likely challenge is that heuristics to determine properties-vs-delegating creator choose differently from your expectations. One other clarification: does "with -parameters" mean that you explicitly disabled inclusion of parameter names from byte code? If so, I do think this should fail since due to lack of annotations, parameter names, heuristics should assume use of "delegating" mode. And in that case, input of JSON Number only would match: not JSON Object. So: I am not sure what the flaw here would be? |
No, compiling with |
Ah. I get confused since some options use plus and minus for on/off. So this makes more sense. |
AFAIK this is a duplicate of FasterXML/jackson-databind#1498. |
Hi, I'm having a similar issue (unannotated single-arg costructor, compiled with -parameters, ParameterNamesModule created with Mode.PROPERTIES) I beleive this was the commit that broke the expected behavior for me: As in Oliver's case, the parameter gets discovered properly, but returning a null Mode prevents its usage. Changing the return value of findCreatorAnnotation (in debug) to the value in creatorBinding (Mode.PROPERTIES in my case) restored the expected behavior. |
Having the same issue. I believe i've traced it to : added a few more checks to the OP's solution to handle this specific case: @Override
public PropertyName findNameForDeserialization(Annotated a) {
if (a instanceof AnnotatedParameter) {
Annotated o = ((AnnotatedParameter) a).getOwner();
if (o instanceof AnnotatedConstructor) {
Constructor<?>[] ctors = o.getRawType().getDeclaredConstructors();
if (ctors.length == 1 && ctors[0].getParameterCount() == 1) {
return PropertyName.construct(findParameterName((AnnotatedParameter) a));
}
}
}
return super.findNameForDeserialization(a);
} |
One thing that may not be mentioned above: @nish-hu I would need (refinement of) exact reproduction, since it sounds like you are creating module with different parameter(s)? @bernstein82 make sure to use description of preferred interpretation instead of "illegal" since different users tend to have different expectations.
is the one to override: return |
@cowtowncoder thanks for clarification on the issue and how to properly handle it (overriding findCreatorAnnotation() was actually what i came up before finding this issue, but after a single debugging session i wasn't exactly sure this was the "correct" solution :-) ) edited my comment above to clarify about DelegatingDeserializer instead of "illegal", by now i understand why it doesn't work as i expected. in FasterXML/jackson-databind#1498 a "fix" was implemented and deferred to release 3.x. So is 3.x imminent? public Mode findCreatorAnnotation(MapperConfig<?> config, Annotated a) { } it get's even harder if one wants to serialize & deserialize using the implicit property names from the implicit jsonconstuctor. (project with way too many classes where field names don't match constuctor param names... surprisingly gson handled that without any configuration) |
Ok. After thinking this through, once again, I think I can come up with something that would resolve the issue:
So, for 2.11, I think what I could add:
However, even while writing this I realized that there are couple of aspects:
Solving first problem would not be something that |
I did a quick test to see what the current behaviour is with parameter names module enabled and there are multiple unannotated constructor:
What is the reason why we would want this?
Adding a setting could be good, but keep in mind that we already have a setting related to this behaviour: see https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names#delegating-creator |
I agree with @WellingR. |
Obviously I have failed to explain anything here, so I will just make a statement: Single-Argument Constructors CAN NOT act the same as multi-argument ones because of the ambiguity. The setting in question CAN NOT solve this problem as it does not induce equivalent of At this point I will revert my earlier thinking of working on this: without credible path forward there is nothing to do for Jackson 2.x. Specifically:
|
Some feedback regarding the disambiguation algorithm: in Spring Data we use the following rules:
|
@odrotbohm This is not unlike what Jackson does actually. One valid case (in principle) that unfortunately can not be supported without major rewrite is that of 1-arg constructor (and no others). Even if that could be detected (databind may be in position to do so), there is no current way to indicate choice between Delegating / Properties-based choice: setting in module is not something databind knows (or can know about) without some additional hook. I suppose there is one way I could see potentially working. Hypothetical:
which would detect un-annotated constructed, if (and only if)
Even this might be a reach since introspection logic in databind does separate handling of 0- and 1-arg constructors. |
So if I understood you correctly, the only way to really fix this is in 3.x.y timeline (FasterXML/jackson-databind#1498)? |
FYI, my specific use case is lombok
However what about a setting |
@lpandzic Unless a very specific combo-fix (one part in jackson-databind, other [possibly] in java8 module), yes. So challenge would be that of restricting scope to -- I think? -- case of 1-argument, non-annotated constructor (and no other constructors). Thinking about this aloud, addition of Builder-style construction in 2.10 and later would allow defining a new configuration setting, which would allow
and with that actually java8 module would not need anything. Now that I wrote this, it actually seems much more doable. WDYT? One thing I lack right now is time to work on things but I sort of like this approach. |
@WellingR I think you are right that drilling into specific problem case could be the way forward. But perhaps my previous comment's suggestion would work the way you are suggesting (although cover couple of related aspects). |
Sounds like a good idea to be able to configure the behaviours. Is there a difference between 1. (current heuristics) and 4. (Heuristics with |
@WellingR It would have slight difference in the specific case of Actually I think (3) and (4) would also differ in that auto-discovery of 1-arg constructor would be enabled without annotation, in addition to case of |
@cowtowncoder Any progress on this? Mode 3 would be perfect for my use-case (lombok value classes). As I would always expect property-based (or actually parameter name based) constructors for those. |
i think my usecase for this feature is the same as @WellingR:
basically my ideal solution would be a configuration option to disable the delegation constructor handling completely (which looks completely obsolete anyway) then it would as simple as looking for a single arg constructor with a matching parameter name. this would even allow handling cases where there are multiple single-arg constructors (don't see a need for that either ;-)) |
@bernstein82 I am not sure why you think delegating constructor is obsolete (although it'd often be used with something like But my working idea right one is to define an enum (to allow extending set of default strategies), backed up by to-be-designed interface for logic to get a set of visible Creator candidates, at least in cases decision is not possible without further info (counter-example being a single applicable annotated Creator method). |
Now that this issue: FasterXML/jackson-databind#1498 has been resolved, to be in Jackson 2.12(.0), I'll close this as a duplicate. |
Take the following domain class on Java 8 compiled with
-parameters
:This test:
fails with:
A couple of more observations:
@ConstructorProperties
) makes the test go green. Unfortunately I don't control the class so that I cannot add any annotations. Also, I thought adding the parameter names module should be sufficient as a name can now be derived from the class and additional annotations shouldn't be needed. I.e. the annotation would just redeclare what's already defined.Mode
explicitly doesn't change anything about the failing test.findNameForDeserialization(…)
which ´ParameterNamesAnnotationIntrospector` does not override. Is that by design? Because if I go ahead and implement that method like this:things start to work again. I can see that this method is supposed to explicitly obtain a name from an annotation but it feels like that path is favored for a one-argument constructor.
The text was updated successfully, but these errors were encountered: