使用 Jackson 将 JSON 反序列化为多态类型 - 一个完整的示例给了我一个编译错误

我正在尝试完成程序员布鲁斯的教程,该教程应该允许多态JSON的反序列化。

完整的列表可以在这里找到 程序员布鲁斯教程 (顺便说一句,很棒的东西)

我已经完成了前五个没有问题,但我在最后一个(示例6)上遇到了一个障碍,这当然是我真正需要工作的一个障碍。

我在编译时收到以下错误

对象映射器类型中的方法 readValue(JsonParser, Class) 不适用于参数(ObjectNode,Class)

它是由代码块引起的

  public Animal deserialize(  
      JsonParser jp, DeserializationContext ctxt)   
      throws IOException, JsonProcessingException  
  {  
    ObjectMapper mapper = (ObjectMapper) jp.getCodec();  
    ObjectNode root = (ObjectNode) mapper.readTree(jp);  
    Class<? extends Animal> animalClass = null;  
    Iterator<Entry<String, JsonNode>> elementsIterator =   
        root.getFields();  
    while (elementsIterator.hasNext())  
    {  
      Entry<String, JsonNode> element=elementsIterator.next();  
      String name = element.getKey();  
      if (registry.containsKey(name))  
      {  
        animalClass = registry.get(name);  
        break;  
      }  
    }  
    if (animalClass == null) return null;  
    return mapper.readValue(root, animalClass);
  }  
} 

特别是按生产线

return mapper.readValue(root, animalClass);

以前有人遇到过这种情况吗?如果是这样,有没有解决方案?

我很感激任何人都可以提前感谢Jon D的任何帮助。


答案 1

正如所承诺的,我将举一个如何使用注释来序列化/反序列化多态对象的示例,我将此示例基于您正在阅读的教程中的类。Animal

首先,你的类带有子类的Json注释。Animal

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "Dog"),

    @JsonSubTypes.Type(value = Cat.class, name = "Cat") }
)
public abstract class Animal {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

然后是您的子类,和 .DogCat

public class Dog extends Animal {

    private String breed;

    public Dog() {

    }

    public Dog(String name, String breed) {
        setName(name);
        setBreed(breed);
    }

    public String getBreed() {
        return breed;
    }

    public void setBreed(String breed) {
        this.breed = breed;
    }
}

public class Cat extends Animal {

    public String getFavoriteToy() {
        return favoriteToy;
    }

    public Cat() {}

    public Cat(String name, String favoriteToy) {
        setName(name);
        setFavoriteToy(favoriteToy);
    }

    public void setFavoriteToy(String favoriteToy) {
        this.favoriteToy = favoriteToy;
    }

    private String favoriteToy;

}

如您所见,和 没有什么特别之处,唯一了解它们的是 类 ,因此在反序列化时,您将以 和 将返回实际实例,如以下测试所示:CatDogabstractAnimalAnimalObjectMapper

public class Test {

    public static void main(String[] args) {

        ObjectMapper objectMapper = new ObjectMapper();

        Animal myDog = new Dog("ruffus","english shepherd");

        Animal myCat = new Cat("goya", "mice");

        try {
            String dogJson = objectMapper.writeValueAsString(myDog);

            System.out.println(dogJson);

            Animal deserializedDog = objectMapper.readValue(dogJson, Animal.class);

            System.out.println("Deserialized dogJson Class: " + deserializedDog.getClass().getSimpleName());

            String catJson = objectMapper.writeValueAsString(myCat);

            Animal deseriliazedCat = objectMapper.readValue(catJson, Animal.class);

            System.out.println("Deserialized catJson Class: " + deseriliazedCat.getClass().getSimpleName());



        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

运行类后的输出:Test

{"@type":"Dog","name":"ruffus","breed":"english shepherd"}

Deserialized dogJson Class: Dog

{"@type":"Cat","name":"goya","favoriteToy":"mice"}

Deserialized catJson Class: Cat

希望这有帮助,

何塞·路易斯


答案 2

在声明类之前只需要一行即可实现正确的多态序列化/反序列化:Animal

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public abstract class Animal {
   ...
}

此行表示:在序列化时添加元属性,或在反序列化 () 上读取名为“@class”() 的元属性,该属性包含完全限定的 Java 类名 ()。include = JsonTypeInfo.As.PROPERTYproperty = "@class"use = JsonTypeInfo.Id.CLASS

因此,如果直接创建 JSON(不进行序列化),请记住添加具有所需类名的元属性“@class”,以便进行正确的反序列化。

更多信息请点击这里