Spring Jackson ObjectMapper не удается десериализовать JSON во время прохождения модульного теста

#spring #jackson

#spring #джексон

Вопрос:

У меня есть класс в моем веб-приложении Spring:

 @Value // or @Data Lombok
public class Bar {
    private final BigDecimal value;

    @JsonCreator
    public Bar(double value) {
        this.value = BigDecimal.valueOf(value);
    }
}

  

Я написал модульный тест, который проходит:

 @Test
void test() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    Bar bar = new Bar(12.34);
    assertEquals(mapper.readValue("12.34", Bar.class), bar);
}
  

Но когда я отправляю POST контроллеру, ему не удается десериализовать тело запроса (которое просто 12.34 должно быть десериализовано в Bar экземпляр) со следующей ошибкой:

Ошибка синтаксического анализа JSON: не удается создать экземпляр com.example.demo.Bar (хотя существует хотя бы один создатель): нет конструктора double / с двойным аргументом / заводского метода для десериализации из числового значения (12.34); вложенным исключением является com.fasterxml.jackson.databind.exc.MismatchedInputException: Не удается создать экземпляр com.example.demo.Bar (хотя существует хотя бы один создатель): нет конструктора double / с двойным аргументом / заводского метода для десериализации из числового значения (12.34 )

Если я удалю @Value , он может десериализовать его. Чтобы сделать это еще более запутанным, если я добавлю конструктор (созданный @Value ) вручную, он все равно будет работать. Но если я удалю @JsonCreator его снова, он сможет десериализовать его. Чего мне не хватает?

Ответ №1:

@Jsoncreator следует использовать в сочетании с @JsonProperty , чтобы указать, как десериализовать объект JSON. Итак, если, например, у вас есть контроллер rest, который нравится некоторым JSON:

 {
  "value": 123
}
  

Ваш конструктор должен быть аннотирован следующим образом:

 @JsonCreator
public Bar(@JsonProperty("value") double value) {
    this.value = BigDecimal.valueOf(value);
}
  

Хотя это может показаться избыточным, идея в том, что это обеспечивает большую гибкость в случаях, когда JSON, который вы собираетесь десериализовать, не соответствует имени ваших свойств.

Так, например, если получаемый вами объект все еще имеет ключевое значение, но у вашего класса есть свойство myValue , будет работать следующее:

 public class Example {
    private final BigDecimal myValue;

    @JsonCreator
    public Bar(@JsonProperty("value") double myValue) {
        this.myValue= BigDecimal.valueOf(myValue);
    }
}
  

Комментарии:

1. Хм, это не вся история (по крайней мере, на основе документов). Тем не менее, это не объясняет, почему модульный тест проходит, тогда как spring app завершается с ошибкой.