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.