使用Jackson反序列化为多态集合而不使用@JsonTypeInfo [英] Deserialize into polymorphic collection using Jackson without using @JsonTypeInfo

查看:594
本文介绍了使用Jackson反序列化为多态集合而不使用@JsonTypeInfo的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用第三方服务,它将JSON吐出,我正在尝试将其反序列化为Java POJO。 JSON服务无法更改,我正在使用Java 8和Jackson 2.4。

I am using a 3rd party service that spits out JSON which I'm trying to deserialize into Java POJOs. The JSON service can't be changed and I'm using Java 8 and Jackson 2.4.

这是我的问题的简化版本。我有一个接口和下面两个具体的类:

Here is a simplified version of my problem. I have an interface and two concrete classes below:

public interface Animal {

}

public class Dog implements Animal {

   public String bark;

}

public class Cat implements Animal {

   public String meow;

}

我需要将以下JSON反序列化为列表< Animal>

I need to deserialize the following JSON into a List<Animal>:

 {
        "animals": [
     {
       "bark":"bowwow"
     },
     {
      "bark":"woofWoof"
     },
     {
      "meow":"meeeOwww"
     },
     {
      "meow":"hisssss"
     }
    ]
}

我希望能够根据喵喵属性(它是猫)的存在来确定具体的java类型JSON中的bark属性(它是一个Dog)。如何让杰克逊这样做?

I want to be able to determine the concrete java type based on the existence of the meow property (its a Cat) and the bark property (its a Dog) in the JSON. How can make I Jackson do this?

推荐答案

可以通过 StdDeserializer

public class UniquePropertyPolymorphicDeserializer<T> extends StdDeserializer<T> {

    private Map<String, Class<? extends T>> registry;

    public UniquePropertyPolymorphicDeserializer(Class<T> clazz) {
        super(clazz);
        registry = new HashMap<String, Class<? extends T>>();
    }

    public void register(String uniqueProperty, Class<? extends T> clazz) {
        registry.put(uniqueProperty, clazz);
    }

    @Override
    public T deserialize(JsonParser p, DeserializationContext ctxt) 
            throws IOException, JsonProcessingException {

        Class<? extends T> clazz = null;

        ObjectMapper mapper = (ObjectMapper) p.getCodec();  
        ObjectNode obj = (ObjectNode) mapper.readTree(p);  
        Iterator<Entry<String, JsonNode>> elementsIterator = obj.fields();

        while (elementsIterator.hasNext()) {  
            Entry<String, JsonNode> element = elementsIterator.next();  
            String name = element.getKey();  
            if (registry.containsKey(name)) {  
                clazz = registry.get(name);  
                break;  
            }
        }

        if (clazz == null) {
            throw ctxt.mappingException(
                    "No registered unique properties found "
                    + "for polymorphic deserialization");  
        }

        return mapper.treeToValue(obj, clazz);
    }
}

可以使用如下:

String json = "[{\"bark\":\"bowwow\"},{\"bark\":\"woofWoof\"},{\"meow\":\"meeeOwww\"},{\"meow\":\"hisssss\"}]";

UniquePropertyPolymorphicDeserializer<Animal> deserializer = 
    new UniquePropertyPolymorphicDeserializer<>(Animal.class);

deserializer.register("bark", Dog.class); // if "bark" field is present, then it's a Dog
deserializer.register("meow", Cat.class); // if "meow" field is present, then it's a Cat

SimpleModule module = new SimpleModule("UniquePropertyPolymorphicDeserializer", 
        new Version(1, 0, 0, null, "com.example", "polymorphic-deserializer")); 
module.addDeserializer(Animal.class, deserializer);

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);

Animal[] animals = mapper.readValue(json, Animal[].class);

有关详细信息,请查看这里

For more details, have a look here.

这篇关于使用Jackson反序列化为多态集合而不使用@JsonTypeInfo的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆