编辑:如果您可以使用最新的 Jackson 候选版本,您的问题就解决了。我在这里组装了一个快速演示 https://github.com/MariusSchmidt/de.denktmit.stackoverflow/tree/main/de.denktmit.jackson
您应该 https://github.com/FasterXML/jackson-databind/issues/1627 查看此线程,因为它讨论了您的问题并提出了解决方案。有一个合并,对我来说看起来很有希望 https://github.com/FasterXML/jackson-databind/pull/2813。因此,您可以尝试遵循@JsonTypeInfo(使用=推断)的路径。
但是,如果您无法使用最新即将推出的杰克逊版本,那么我可能会这样做:
向后移植合并请求,或
- 使用 Jackson 将输入反序列化为通用 JsonNode
- 使用 https://github.com/json-path/JsonPath 检查是否存在一个或多个属性。某些容器类可以包装唯一标识类类型所需的所有路径。
- 将 JsonNode 映射到确定的类,如此处所述 将 JsonNode 转换为 POJO
通过这种方式,您可以充分利用 Jackson 的全部功能,而无需处理低级映射逻辑。
此致敬意
马吕斯
动物
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Bird;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Fish;
import org.junit.jupiter.api.Test;
import java.util.List;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id.DEDUCTION;
import static org.assertj.core.api.Assertions.assertThat;
@JsonTypeInfo(use = DEDUCTION)
@JsonSubTypes( {@JsonSubTypes.Type(Bird.class), @JsonSubTypes.Type(Fish.class)})
public class Animal {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
鸟
public class Bird extends de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal {
private double wingspan;
public double getWingspan() {
return wingspan;
}
public void setWingspan(double wingspan) {
this.wingspan = wingspan;
}
}
鱼
public class Fish extends de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal {
private boolean freshwater;
public boolean isFreshwater() {
return freshwater;
}
public void setFreshwater(boolean freshwater) {
this.freshwater = freshwater;
}
}
动物园围栏
public class ZooPen {
private String type;
private List<de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal> animals;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal> getAnimals() {
return animals;
}
public void setAnimals(List<de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal> animals) {
this.animals = animals;
}
}
测试
import com.fasterxml.jackson.databind.ObjectMapper;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Bird;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Fish;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class DeductivePolymorphicDeserializationTest {
private static final String birdString = "{\n" +
" \"name\": \"Tweety\",\n" +
" \"age\": 79,\n" +
" \"wingspan\": 2.9\n" +
" }";
private static final String fishString = "{\n" +
" \"name\": \"Nemo\",\n" +
" \"age\": 16,\n" +
" \"freshwater\": false\n" +
" }";
private static final String zooPenString = "{\n" +
" \"type\": \"aquaviary\",\n" +
" \"animals\": [\n" +
" {\n" +
" \"name\": \"Tweety\",\n" +
" \"age\": 79,\n" +
" \"wingspan\": 2.9\n" +
" },\n" +
" {\n" +
" \"name\": \"Nemo\",\n" +
" \"age\": 16,\n" +
" \"freshwater\": false\n" +
" }\n" +
" ]\n" +
"}";
private final ObjectMapper mapper = new ObjectMapper();
@Test
void deserializeBird() throws Exception {
de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal animal = mapper.readValue(birdString, de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal.class);
assertThat(animal).isInstanceOf(de.denktmit.stackoverflow.jackson.polymorphic.deductive.Bird.class);
}
@Test
void deserializeFish() throws Exception {
de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal animal = mapper.readValue(fishString, de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal.class);
assertThat(animal).isInstanceOf(de.denktmit.stackoverflow.jackson.polymorphic.deductive.Fish.class);
}
@Test
void deserialize() throws Exception {
de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen zooPen = mapper.readValue(zooPenString, de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen.class);
assertThat(zooPen).isInstanceOf(de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen.class);
}
}