Другими словами, существует ли предел глубины наследования, которого можно достичь.
В настоящее время я нахожусь на глубине 2, дедушка и бабушка -> родитель -> ребенок, и я сталкиваюсь с проблемой, когда Джексон может десериализоваться до родителя, а затем выдает UnrecognizedPropertyException. Это было бы правильно, однако дочерний класс обладает этим свойством, и я считаю, что добавил правильную информацию о типе для Джексона, чтобы десериализовать дочерний элемент.
Этот тест показывает проблему:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Value;
import lombok.experimental.SuperBuilder;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
public class JacksonInheritanceTest {
@Test
public void deserializeChildrenAsGrandParentList() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String grandparentsJson = "{" +
"\"list\":[{" +
"\"type\": \"parent\"," +
"\"value\": \"child\"," +
"\"someProperty\": \"foobar\"" +
"}]" +
"}";
GrandParentList grandparents = mapper.readValue(grandparentsJson, GrandParentList.class);
Assert.assertNotNull(grandparents);
}
@Test
public void deserializeParentAsGrandParent() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String parentJson = "{" +
"\"type\": \"parent\"," +
"\"value\": \"child\"" +
"}";
GrandParent grandparent = mapper.readValue(parentJson, GrandParent.class);
Assert.assertNotNull(grandparent);
}
@Test
public void deserializeChildAsGrandParent() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String grandparentJson = "{" +
"\"type\": \"parent\"," +
"\"value\": \"child\"," +
"\"someProperty\": \"foobar\"" +
"}";
GrandParent grandparent = mapper.readValue(grandparentJson, GrandParent.class);
Assert.assertNotNull(grandparent);
}
@Test
public void deserializeChildAsParent() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String childJson = "{" +
"\"type\": \"parent\"," +
"\"value\": \"child\"," +
"\"someProperty\": \"foobar\"" +
"}";
Parent parent = mapper.readValue(childJson, Parent.class);
Assert.assertNotNull(parent);
}
@Test
public void deserializeAsChild() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String child1 = "{" +
"\"type\": \"parent\"," +
"\"value\": \"child\"," +
"\"someProperty\": \"foobar\"" +
"}";
Child child = mapper.readValue(child1, Child.class);
Assert.assertNotNull(child);
}
}
class GrandParentList {
@JsonProperty
List<GrandParent> list;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = Parent.class,
name = "parent")
})
@Getter
@SuperBuilder
@JsonDeserialize(builder = GrandParent.GrandParentBuilderImpl.class)
class GrandParent {
@JsonProperty("type")
private String type;
@JsonPOJOBuilder(withPrefix = "")
static final class GrandParentBuilderImpl extends GrandParentBuilder<GrandParent, GrandParent.GrandParentBuilderImpl> {
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "value", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = Child.class, name = "child")
})
@Getter
@SuperBuilder
@JsonDeserialize(builder = Parent.ParentBuilderImpl.class)
class Parent extends GrandParent {
@JsonProperty
private String value;
@JsonPOJOBuilder(withPrefix = "")
static final class ParentBuilderImpl extends ParentBuilder<Parent, ParentBuilderImpl> {
}
}
@EqualsAndHashCode(callSuper = true)
@Value
@SuperBuilder
@JsonDeserialize(builder = Child.ChildBuilderImpl.class)
class Child extends Parent {
@JsonProperty
private String someProperty;
@JsonPOJOBuilder(withPrefix = "")
static final class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
}
}
Этот пример полный, но не минимальный. что бы я ни знал, пока нет предела, мне кажется, что вы не определили «дочерний элемент» как подкласс прародителя или родителя, а дочерний элемент не аннотирован с помощью jsontype. еще пример jsonTypeName: stackoverflow.com/questions/56395909/…




Установите конфигурацию для объекта ObjectMapper:
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
К сожалению, это не ответ на мой вопрос. Так как это приведет к тому, что Джексон просто проигнорирует свойство ChildsomeProperty и вернет экземпляр Parent вместо Child. Это не то поведение, которое я ожидаю.
Вот как определить наследование со многими уровнями:
Вы хотите десериализовать список GrandParent, конечный тип которого является «дочерним».
{
"list":[{
"type": "child",
"someProperty": "foobar"
}]
}
и дерево наследования:
GrandParent
Parent
Child(someProperty:String)
Вы должны определить свой атрибут «тип» на верхнем уровне, @JsonTypeInfo(...) вы можете повторить это на подуровнях, но это не требуется, если вы сериализуете/десериализуете только дедушку и бабушку. Затем на каждом родительском уровне (классы Parent и GrandParent) вы определяете подтипы так же, как вы это делали с @JsonSubTypes.
код
public class JacksonInheritanceTest2 {
@Test
public void deserializeChildrenAsGrandParentList() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String grandparentsJson = "{" +
"\"list\":[{" +
"\"type\": \"child\"," +
"\"someProperty\": \"foobar\"" +
"}]" +
"}";
GrandParentList grandparents = mapper.readValue(grandparentsJson, GrandParentList.class);
Assertions.assertNotNull(grandparents);
}
}
class GrandParentList {
@JsonProperty
List<GrandParent> list;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = Parent.class,name = "parent"),
//@JsonSubTypes.Type(value = Child.class, name = "child")
})
class GrandParent {
@JsonProperty("type")
private String type;
}
//@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = Child.class, name = "child")
})
class Parent extends GrandParent {
@JsonProperty
private String value;
}
@JsonSubTypes({
@JsonSubTypes.Type(value = Child.class, name = "child")
})
class Child extends Parent {
@JsonProperty
private String someProperty;
public String getSomeProperty() {
return someProperty;
}
public void setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}
}
Ошибка, которую вы сделали:
Боковой узел: Assertions от junit5, он делает то же, что и Assert от junit4
Так что если я правильно понимаю. Джексон из коробки может обрабатывать вывод типа только на основе одного имени свойства? Моя проблема в том, что мне нужно сделать вывод типа на основе двух свойств, а не одного. Я предположил, что добавление @JsonTypeInfo к разным глубинам наследования позволит Джексону сделать вывод, какое свойство будет отображаться на какую глубину, и соединить их вместе. К сожалению, похоже, мне нужно написать что-то специальное для этого. Спасибо за ответ!
@ByeBye нет, вывод типа работает должным образом, ваш объект имеет только один тип за раз. Вы не можете указать 2 типа для объекта (как бы вы поступили с java-кодом?)
@ByeBy, может быть, я мог бы объяснить, как работает самоанализ: 1. вы даете класс дедушки и бабушки с его конфигурацией 2. Джексон находит аннотацию к классу -> получает имя типа объекта - затем рекурсивно сканирует, чтобы найти реальный класс, связанный с это имя 3. Джексон создает экземпляр этого класса (не нужно знать промежуточный класс Parent на этом уровне) 3. это влияет на все найденные поля, дающие дочерний класс - снова все поля Parent известны по наследству - не нужно укажите Родитель. Во всех тезисах 3 шага вам никогда не нужно указывать, что экземпляр «Дочерний» является «Родительским».
Да, это то, что я имел в виду. Я могу указать информацию о типе в аннотации только один раз (на GrandParent), и я могу использовать только одно свойство для вывода типа (свойство type). Я отмечу ваш ответ как ответ. Спасибо.
Если бы он не сделал больше двух, у него возникла бы проблема, а если у вас больше четырех, у вас возникла бы проблема.