Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Jackson多态性:嵌套子类型_Java_Json_Jackson_Polymorphism_Jackson Databind - Fatal编程技术网

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();`,无法找出异常出现的原因。