使用Jackson反序列化为多态集合而不使用@JsonTypeInfo

时间:2016-07-20 21:15:15

标签: java json jackson

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

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

public interface Animal {

}

public class Dog implements Animal {

   public String bark;

}

public class Cat implements Animal {

   public String meow;

}

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

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

我希望能够根据JSON中存在的meow属性(它是Cat)和bark属性(它是一个Dog)来确定具体的java类型。怎么能让杰克逊这样做呢?

1 个答案:

答案 0 :(得分:1)

可以使用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);

有关详细信息,请查看here