Не могу правильно десериализовать JSON, используя @JsonCreator, как описано в Javadoc - PullRequest
0 голосов
/ 09 февраля 2020

Мне трудно понять, как работает аннотация Джексона @JsonCreator (особенно с различными режимами).

Я пытался максимально упростить:

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);
        // Throws here: 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)

        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);
        // Throws here: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "inner" (class Inner), not marked as ignorable (one known property: "prop"])

        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);
        // Throws here: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "inner" (class Inner), not marked as ignorable (one known property: "prop"])

        assertThat(read).isNotNull();
        assertThat(read.getInner()).isNotNull();
        assertThat(read.getInner().getProp()).isEqualTo("42");
    }

}

Мой классы объектов:

public class Wrapper {

    private Inner inner;

    @JsonCreator
    public Wrapper(Inner inner) {
        this.inner = inner;
    }

    public Inner getInner() {
        return inner;
    }

}

и

public class Inner {

    private String prop;

    @JsonCreator
    public Inner(String prop) {
        this.prop = prop;
    }

    public String getProp() {
        return prop;
    }

}

Выдержки из @JsonCreator Javado c:

ПРИМЕЧАНИЕ: при аннотировании методов-создателей (конструкторов) , фабричные методы), метод должен быть либо:

• Метод конструктора / фабрики с одним аргументом без JsonPropertyannotation для аргумента: если это так, это так называемый «создатель делегата», в этом случае Джексон сначала связывается JSON в тип аргумента, а затем вызывает создателя. Это часто используется вместе с JsonValue (используется для сериализации).

... и из аргумента mode:

Значение по умолчанию для Mode.DEFAULT означает, что вызывающая сторона должна использовать стандартную эвристику для выбора используемого режима.

com.fasterxml.jackson.annotation.JsonCreator.Mode.DEFAULT Javado c:

Псевдо-режим, который указывает, что вызывающий абонент должен использовать эвристику по умолчанию для выбора используемого режима. Это обычно способствует использованию режима делегирования для создателей с одним аргументом, которые принимают структурированные типы.

Что я сделал не так в этих объяснениях?

Я использую Jackson 2.9.9.20190807, как указано 1 pom. xml от Spring Boot, который мы используем.

1 Ответ

0 голосов
/ 09 февраля 2020

Признаюсь, я не знаком с режимами JsonCreator. Однако тесты проходят успешно, если вы аннотируете аргументы конструкторов с помощью имен свойств.

Обоснование заключается в том, что имена аргументов являются необязательными настройками компилятора, поэтому возможно, что Джексон не сможет прочитать имя аргумента через отражение и, следовательно, невозможно присвоить десериализованное значение этому аргументу

public class Wrapper {

    private Inner inner;

    @JsonCreator
    public Wrapper(@JsonProperty("inner") Inner inner) {
        this.inner = inner;
    }

    public Inner getInner() {
        return inner;
    }

}

public class Inner {

    private String prop;

    public Inner(@JsonProperty("prop") String prop) {
        this.prop = prop;
    }

    public String getProp() {
        return prop;
    }

}
...