#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 завершается с ошибкой.