Это связано со странным поведением Джексона добавить дополнительное поле, невидимое для вас во время компиляции, чтобы различать guish между подклассами, названными как значение, которое вы указали в @JsonTypeInfo
. Поскольку ваш родительский класс содержит свойство, сериализованное в свойство JSON с именем objectType
, а имя знаменателя, указанное в @JsonTypeInfo
, также равно objectType
. Если бы вы сериализовали объект Child
, вы заметили бы, что сериализованный объект содержит два поля с одинаковым именем objectType
, где будет заполнено только одно из них:
System.out.println(objectMapper.writeValueAsString(new Child()));
приводит к
{"objectType":"child","objectType":null,"field1":null,"field2":null}
Обходной путь - пропустить явное поле productType
(сериализованное как objectType
) в родительском классе, если оно не требуется в вашем коде, или назначить другое имя для сериализации (например, productType
), но тогда вам, конечно, нужно иметь второе поле JSON, которое необходимо десериализовать в него:
Изменение
public class Parent {
@JsonProperty("objectType")
private String productType;
на
public class Parent {
@JsonProperty("productType")
private String productType;
и
Parent parent = objectMapper.treeToValue(objectMapper.readTree("{\n" +
" \"objectType\" : \"child\",\n" +
" \"productType\" : \"child\",\n" +
" \"field1\" : \"value1\",\n" +
" \"field2\" : \"value2\"\n" +
"}"), Parent.class);
System.out.println(parent.getProductType());
приводит к выводу
child
Третья возможность - это явная инициализация поля, например, через конструктор, поскольку Джексон использует конструктор по умолчанию для создания объектов при десериализации:
// For subclasses
protected Parent (String productType) {
this.productType = productType;
}
// For Jackson
public Parent () {
}
и
public Child () {
super("child");
}
Редактировать: я использовал String
вместо ProductType
, чтобы упростить мой код, но результат похож.