Java Jackson多态性:嵌套子类型
是否可以以嵌套方式使用多个Java Jackson多态性:嵌套子类型,java,json,jackson,polymorphism,jackson-databind,Java,Json,Jackson,Polymorphism,Jackson Databind,是否可以以嵌套方式使用多个@JsonSubType注释 例如,设想以下类: @数据 @JsonSubTypeInfo(include=As.EXISTING_PROPERTY,PROPERTY=“species”,use=Id.NAME,visible=true) @JsonSubTypes({ @类型(name=“Dog”,value=Dog.class) @类型(name=“Cat”,value=Cat.class) }) 公共抽象类动物{ 私有字符串名称; 私有串种; } @数据 @Js
@JsonSubType
注释
例如,设想以下类:
@数据
@JsonSubTypeInfo(include=As.EXISTING_PROPERTY,PROPERTY=“species”,use=Id.NAME,visible=true)
@JsonSubTypes({
@类型(name=“Dog”,value=Dog.class)
@类型(name=“Cat”,value=Cat.class)
})
公共抽象类动物{
私有字符串名称;
私有串种;
}
@数据
@JsonSubTypeInfo(include=As.EXISTING_PROPERTY,PROPERTY=“breed”,use=Id.NAME,visible=true)
@JsonSubTypes({
@类型(name=“Labrador”,value=Labrador.class)
@类型(name=“Bulldog”,value=Bulldog.class)
})
公共抽象类狗扩展了动物{
私家犬;
}
@数据
公营猫科动物{
私有布尔lovesCatnip;
}
@数据
公共级拉布拉多犬{
私有字符串颜色;
}
@数据
公营牛头犬{
私有字符串类型;//“法语”、“英语”等。。
}
如果我使用对象映射器,我可以成功地将Bulldog
映射到JSON,但是,当尝试读取结果JSON并将其读回时,会出现如下错误:
Can not construct instance of com.example.Dog abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
有没有可能让Jackson使用这样的子类型?我是否需要为每个子类创建自定义反序列化程序
编辑:
我已经从最初的帖子中稍微修改了上面的类。我添加了一个Cat
类,并让它和Dog
从Animal
扩展而来
下面是一个可以使用ObjectMapper::writeValueAsString
创建的JSON示例:
{
"name": null,
"species": "Dog",
"breed": "Bulldog",
"type": "B-Dog"
}
如果我使用
@JsonTypeInfo
和与您类似的设置,那么下面的代码就可以工作。可能您的问题出在反序列化代码中,请看一下:
public class MyTest {
@Test
public void test() throws IOException {
final Bulldog bulldog = new Bulldog();
bulldog.setBreed("Bulldog");
bulldog.setType("B-Dog");
final ObjectMapper om = new ObjectMapper();
final String json = om.writeValueAsString(bulldog);
final Dog deserialized = om.readValue(json, Dog.class);
assertTrue(deserialized instanceof Bulldog);
}
@JsonTypeInfo(include = As.EXISTING_PROPERTY, property = "species", use = Id.NAME, visible = true)
@JsonSubTypes({
@Type(name = "Dog", value = Dog.class),
@Type(name = "Cat", value = Cat.class)
})
public static abstract class Animal {
private String name;
private String species;
}
@JsonTypeInfo(include = As.EXISTING_PROPERTY, property = "breed", use = Id.NAME, visible = true)
@JsonSubTypes({
@Type(name = "Labrador", value = Labrador.class),
@Type(name = "Bulldog", value = Bulldog.class)
})
public static abstract class Dog {
private String breed;
public String getBreed() {
return breed;
}
public void setBreed(final String breed) {
this.breed = breed;
}
}
public static abstract class Cat {
private String name;
}
public static class Labrador extends Dog {
private String color;
public String getColor() {
return color;
}
public void setColor(final String color) {
this.color = color;
}
}
public static class Bulldog extends Dog {
private String type; // "frenchy", "english", etc..
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
}
}
为更新的问题编辑:如果您可以为继承层次结构使用相同的属性(在下面的代码中为隐藏属性“@class”),则它可以工作:
@Test
public void test() throws IOException {
final Bulldog bulldog = new Bulldog();
// bulldog.setSpecies("Dog");
// bulldog.setBreed("Bulldog");
bulldog.setType("B-Dog");
final ObjectMapper om = new ObjectMapper();
final String json = om.writeValueAsString(bulldog);
final Animal deserialized = om.readValue(json, Animal.class);
assertTrue(deserialized instanceof Bulldog);
}
@JsonTypeInfo(include = As.PROPERTY, use = Id.CLASS, visible = false)
@JsonSubTypes({
@Type(Dog.class),
@Type(Cat.class)
})
public static abstract class Animal {
}
@JsonTypeInfo(include = As.PROPERTY, use = Id.CLASS, visible = false)
@JsonSubTypes({
@Type(name = "Labrador", value = Labrador.class),
@Type(name = "Bulldog", value = Bulldog.class)
})
public static abstract class Dog
extends Animal {
}
如果要设置动物类型(例如,计算物种、品种等),也可以使用此设置:
@Test
public void test() throws IOException {
final Bulldog bulldog = new Bulldog();
bulldog.setAnimalType("Bulldog");
// bulldog.setSpecies("Dog");
// bulldog.setBreed("Bulldog");
bulldog.setType("B-Dog");
final ObjectMapper om = new ObjectMapper();
final String json = om.writeValueAsString(bulldog);
System.out.println(json);
final Animal deserialized = om.readValue(json, Animal.class);
assertTrue(deserialized instanceof Bulldog);
}
@JsonTypeInfo(include = As.EXISTING_PROPERTY, property = "animalType", use = Id.NAME, visible = true)
@JsonSubTypes({
@Type(Dog.class)
})
public static abstract class Animal {
private String animalType;
public String getAnimalType() {
return animalType;
}
public void setAnimalType(final String animalType) {
this.animalType = animalType;
}
}
@JsonTypeInfo(include = As.EXISTING_PROPERTY, property = "animalType", use = Id.NAME, visible = true)
@JsonSubTypes({
@Type(value = Bulldog.class)
})
public static abstract class Dog
extends Animal {
}
@JsonTypeName("Bulldog")
public static class Bulldog extends Dog {
private String type; // "frenchy", "english", etc..
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
}
我能够解决这个问题,从而将以下JSON转换为
Bulldog
对象:
{
"species": "Dog",
"breed": "Bulldog",
"name": "Sparky",
"type": "English"
}
我使用以下代码来执行此操作:
ObjectMapper om=new ObjectMapper();
addHandler(新的反序列化ProblemHandler(){
@凌驾
公共对象handleMissingInstallator(反序列化上下文ctxt、类instClass、JsonParser p、字符串msg)引发IOException{
JsonNode o=p.readValueAsTree();
JsonNode copy=o.deepCopy();
JsonNode物种=o.get(“物种”);
if(物种!=null){
类您是否正确设置了“繁殖”属性?您是否可以发布如何编写和读取JSON,即异常发生的代码?使用下面发布的示例类,稍作修改(使用狗和猫扩展动物,并调用集合物种),我打印了json
,得到了以下信息:{“name”:null,“species”:“Dog”,“breed”:“Bulldog”,“type”:“B-Dog”}
啊,所以在你的测试中,你调用om.readValue(json,Dog.class)
-我试图做的是om.readValue(json,Animal.class)
。您的狗
和猫
类也不会扩展动物
。如果我做了这些更改(同时调用斗牛犬.setSpecies(“狗”)
)然后我得到了我发布的错误。是的,有了这样的更改,它是可复制的。请参阅我更新的答案。是的,这似乎是可行的,但它不会产生理想的JSON。没有@class
,有可能解决这个问题吗?我的理想情况是有如下JSON:{“物种”:“狗”,“品种”:“斗牛犬”,“name”:“Sparky”,“type”:“English”}
我想不是,可能使用自定义序列化程序更容易,也可以看到以下答案:尼斯提示`parser.nextToken();`,无法找出异常出现的原因。