OK Tatu, thanks for this start of an explanation.

So basically what you're saying is the default `JsonCreator.Mode.DEFAULT` 
does not make the right "guess", despite what says the Javadoc, or maybe I 
wrongly understood it?

public @interface JsonCreator
{
    /**
     * Property that is used to indicate how argument(s) is/are bound for 
creator,
     * in cases there may be multiple alternatives. Currently the one case 
is that
     * of a single-argument creator method, for which both so-called 
"delegating" and
     * "property-based" bindings are possible: since
     * delegating mode can not be used for multi-argument creators, the 
only choice
     * there is "property-based" mode.
     * Check {@link Mode} for more complete explanation of possible choices.
     *<p>
     * Default value of {@link Mode#DEFAULT} means that caller is to use 
standard
     * heuristics for choosing mode to use.
     * 
     * @since 2.5
     */
    public Mode mode() default Mode.DEFAULT;

        /**
         * Pseudo-mode that indicates that caller is to use default 
heuristics for
         * choosing mode to use. This typically favors use of delegating 
mode for
         * single-argument creators that take structured types.
         */
        DEFAULT,

What does that mean "caller is to use default heuristics"?
Am I the caller (or caller code's coder...)? So am I supposed to 
effectively choose a specific mode and not use the DEFAULT one?

Another thing is that due to how I'm gonna structure my different classes 
(my example is just a simplified view) I can't/don't want to use 
@JsonProperty

If I modify the example given above (in the SO link) as follows:

    public class Wrapper {
    
        private Inner inner;
    
        @JsonCreator(mode = Mode.DELEGATING)
        public Wrapper(Inner inner) {
            this.inner = inner;
        }
    
        public Inner getInner() {
            return inner;
        }
    
    }

    public class Inner {
    
        private String prop;
    
        @JsonCreator(mode = Mode.DELEGATING)
        public Inner(String prop) {
            this.prop = prop;
        }
    
        public String getProp() {
            return prop;
        }
    
    }

    public class JacksonDeserialization {
    
        private ObjectMapper om = new ObjectMapper();
    
        @Test // 1
        public void test_deserialization_emptyJson() throws 
JsonParseException, JsonMappingException, IOException {
            Wrapper read = om.readValue("{}", Wrapper.class);    
            assertThat(read).isNotNull();
            assertThat(read.getInner()).isNull();
        }
    
        @Test // 2
        public void test_deserialization_innerIsEmpty() throws 
JsonParseException, JsonMappingException, IOException {
            Wrapper read = om.readValue("{\"inner\":{}}", Wrapper.class);
            assertThat(read).isNotNull();
            assertThat(read.getInner()).isNotNull();
        }
    
        @Test // 3
        public void test_deserialization_innerIsSet() throws 
JsonParseException, JsonMappingException, IOException {
            Wrapper read = om.readValue("{\"inner\":{\"prop\":\"42\"}}", 
Wrapper.class);
            assertThat(read).isNotNull();
            assertThat(read.getInner()).isNotNull();
            assertThat(read.getInner().getProp()).isEqualTo("42");
        }
        
    }

I get three times the same exception:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot 
construct instance of `Inner` (although at least one Creator exists): 
cannot deserialize from Object value (no delegate- or property-based Creator
)
 at [Source: (String)"{}"; line: 1, column: 2]

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot 
construct instance of `Inner` (although at least one Creator exists): 
cannot deserialize from Object value (no delegate- or property-based Creator
)
 at [Source: (String)"{"inner":{}}"; line: 1, column: 2]

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot 
construct instance of `Inner` (although at least one Creator exists): 
cannot deserialize from Object value (no delegate- or property-based Creator
)
 at [Source: (String)"{"inner":{"prop":"42"}}"; line: 1, column: 2]

I still don't get what I'm doing wrong...

maxxyme

On Thursday, April 2, 2020 at 2:34:04 AM UTC+2, Tatu Saloranta wrote:
>
> On Wed, Apr 1, 2020 at 5:24 PM maxxyme _ <[email protected] <javascript:>> 
> wrote: 
> > 
> > Hello, 
> > 
> > I already posted a question on SO but unfortunately didn't get any 
> relevant answer (just one, and the guy told he's not keen on 
> @JsonCreator...) 
> > Everything's detailed there (Java classes & call code): 
> > 
> https://stackoverflow.com/questions/60132067/cant-properly-deserialize-json-using-jsoncreator-as-described-in-the-javadoc
>  
> > 
> > If someone's willing to point me to what's wrong with my class 
> definitions, esp. with the 2 distinct exceptions: 
> > - I don't understand the 1st one (why doesn't it works...?) 
> > - For what I understand from the 2nd, Jackson tries to deserialize the 
> whole JSON as for the Inner object... but why? 
>
> Because there are 2 different possibilities of what might be expected. 
>
> POJO1: expect JSON Object with same properties as POJO: 
>
> public class Pojo1 { 
>    public int x, y; 
>
>    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 
>    public Pojo(@JsonProperty("x") int x0, @JsonProperty("y") int y0) { 
>       x = x0; 
>       y = y0; 
>    } 
> } 
>
> JSON that can be read: {"x":1, "y":2} 
>
> POJO 2: expect JSON _value_ that is used to construct POJO, but is not 
> property-based (often not JSON Object, but may be) 
>
> public class Pojo2 { 
>    int x, y; 
>
>   @JsonCreator(mode = JsonCreator.Mode.DELEGATING) 
>   public Pojo2(/* Note: NO property name */ int[] args) { 
>      x = args[0]; 
>      y = args[1]; 
>   } 
> } 
>
> JSON that can be read: [1, 2] 
>
> ------------- 
>
> So far so good? One thing to note is that "delegating" style is only 
> applicable with just one parameter for constructor (or factory 
> method); whereas "properties" style works for any number. 
>
> But this means that the special case of 1 argument constructor (or 
> factory method) can be ambiguous if `mode` is not specified. With 
> this: 
>
> class NameBean { 
>    private String name; 
>
>    @JsonCreator 
>    public NameBean(String name) { 
>        this.name = name; 
>    } 
> } 
>
> which JSON should this map to/from: 
>
> { "name" : "Bob" } 
>
> OR 
>
> "Bob" 
>
> ? 
>
> There is no good way to figure out that I am aware of. Heuristics 
> fail; and as the answer at SO mentioned, parameter names for 
> constructors may or may not be included even on Java 8 (and were never 
> included before that; Jackson still only requires Java 7 for 
> databind). 
>
> This is why you need to either add the `mode` property OR add explicit 
> `@JsonProperty` for constructor parameter if you want to force 
> Properties-style Creator. 
> And if conversely you want delegating style, mode. 
>
> I hope this helps, 
>
> -+ Tatu +- 
>

-- 
You received this message because you are subscribed to the Google Groups 
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jackson-user/4e07dcf0-74f3-4bcb-b669-5a2f16256d2c%40googlegroups.com.

Reply via email to