Skip to content
This repository has been archived by the owner on Nov 7, 2019. It is now read-only.

Mode.PROPERTIES still does not support single argument constructor. #38

Open
hjohn opened this issue Oct 14, 2017 · 7 comments
Open

Mode.PROPERTIES still does not support single argument constructor. #38

hjohn opened this issue Oct 14, 2017 · 7 comments

Comments

@hjohn
Copy link

hjohn commented Oct 14, 2017

I have a simple class:

public A {
    private final String title;

    public A(String title) {
        this.title = title;
    }
}

When I serialize this (with private field visibility) I get:

{
  "title" : "Alice in Wonderland",
}

When deserializing (with new ParameterNamesModule(Mode.PROPERTIES)) I however get this exception:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of A (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)

What is ambigious here? There is a creator, but it refuses to use it, even though the properties are matches for the parameter names.

If I add a @JsonProperty annotation or a 2nd parameter, the ambiguity disappears. Is it really impossible to tell Jackson to never ever attempt deserializing by passing in a piece of JSON string text? I never want it to use Mode.DELEGATING...

@hjohn
Copy link
Author

hjohn commented Oct 14, 2017

The docs for Mode.PROPERTIES say:

  Note that this mode is currently (2.5) always used for multiple-argument creators; the only ambiguous case is that of a single-argument creator

I take that to mean that Mode.PROPERTIES takes away that ambiguity and assumes that a single argument constructor should be used in the same way a multiple argument constructor would be used...

@cowtowncoder
Copy link
Member

@hjohn Yes, use of mode property with @JsonCreator will force specific choice for annotated creator method. It was added to handle the ambiguity for 1-argument case.

Another thing to try is to use the very latest version -- 2.9.2 -- there is one important fix that affected creator discovery. I do not know if it matters in this case, but it did cause problems with somewhat similar cases.

The exception itself does suggest that constructor may not have been auto-discovered, due to lack of @JsonCreator. Since single-String-argument constructors are actually discovered as delegating creators, in absence of annotations (to support a common case of such usage for many scalar types) this may be used here, although if so, exception message is bit misleading.
This is probably since handling internally does differ between single-String/int/long/boolean constructors, and other "true" delegating creators.

@lpandzic
Copy link
Contributor

Also, @hjohn, take a look at FasterXML/jackson-databind#1498.

@hjohn
Copy link
Author

hjohn commented Oct 15, 2017

I tested it with 2.9.2 -- this made no difference, same exception for the case I presented above.

Adding a @JsonCreator to the only constructor made the exception go away... I was trying to avoid that, the project does not have any jackson dependencies there. Still a bug, but I guess it must be tough to fix with the current architecture as it has been present for a long time.

@cowtowncoder
Copy link
Member

@hjohn Whether it would be considered a bug or not is bit difficult to say just because exact logic for introspecting constructor is... bit fuzzy. This because at the time databinding was written there was no way to find out names of constructor parameters, so auto-detecting property-based constructors would not have been possible, and as such visibility rules alone are not sufficient for determination.
Actual logic has been incrementally improved to try to allow some level of auto-detection but retrofitting is tricky. Some of this will be addressed in 3.0, given that it has Java 8 as baseline and existence of property names can be assumed (within limits that it is possible to compile bytecode without... leading then to other potentially nasty issues -- what to do when names are actually missing).

Anyway. It is still possible for you to achieve no-annotations goal via custom AnnotationIntrospector (either extend .Base, pair with regular; or extend JacksonAnnotationIntrospector).
Just override method findCreatorAnnotation(...) to use logic you like.

@hjohn
Copy link
Author

hjohn commented Oct 16, 2017

Thanks, I only re-reported this as Mode.PROPERTIES documentation seems to say that this issue shouldn't arise. Nothing too hard to work-around. Thanks for the clarification.

@cowtowncoder
Copy link
Member

@hjohn Ah. Yes, documentation is hard, but it should not give the wrong idea.

Btw, the reason why adding @JsonProperty works is because there is heuristic to make @JsonCreator optional in case where all parameters are annotated. But no such thing for "implicit" names (that is, name information from bytecode).
This just for sake of completeness: I think that for Jackson 3.0 it should be possible to allow auto-detection of property-based constructors. Main reason this is not possible with 2.9 is that other users (and some JDK/3rd party types) are using single-arg delegating creators, so breaking change not really practical. There are also security concerns as this could open new vulnerabilities (this is not just theoretical; there are similar reported concerns wrt setters, fields).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants