java - jackson 根据属性名称反序列化

标签 java json jackson jackson-databind

我有以下两种类型的 JSON 对象:

{"foo": "String value"}

{"bar": "String value"}

它们都代表同一基础对象的特殊类型。我如何使用 Jackson 来反序列化它们?类型信息仅由键本身表示,而不是任何键的值(几乎所有示例都使用键的值来确定类型:https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization)

最佳答案

Jackson 不提供 out of the box solution为此,但这并不意味着您不走运。


假设您的类实现了一个公共(public)接口(interface)或扩展了一个公共(public)类,如下所示:

public interface Animal {

}
public class Dog implements Animal {

   private String bark;
   
   // Default constructor, getters and setters
}
public class Cat implements Animal {

   private String meow;
   
   // Default constructor, getters and setters
}

您可以根据属性名称创建自定义反序列化器。它允许您定义一个 unique 属性,该属性将用于查找要执行反序列化的类:

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

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

    public PropertyBasedDeserializer(Class<T> baseClass) {
        super(baseClass);
        deserializationClasses = new HashMap<String, Class<? extends T>>();
    }

    public void register(String property, Class<? extends T> deserializationClass) {
        deserializationClasses.put(property, deserializationClass);
    }

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

        ObjectMapper mapper = (ObjectMapper) p.getCodec();
        JsonNode tree = mapper.readTree(p);
        
        Class<? extends T> deserializationClass = findDeserializationClass(tree);
        if (deserializationClass == null) {
            throw JsonMappingException.from(ctxt, 
               "No registered unique properties found for polymorphic deserialization");
        }

        return mapper.treeToValue(tree, deserializationClass);
    }
    
    private Class<? extends T> findDeserializationClass(JsonNode tree) {
        
        Iterator<Entry<String, JsonNode>> fields = tree.fields();
        Class<? extends T> deserializationClass = null;
        
        while (fields.hasNext()) {
            Entry<String, JsonNode> field = fields.next();
            String property = field.getKey();
            if (deserializationClasses.containsKey(property)) {
                deserializationClass = deserializationClasses.get(property);
                break;  
            }
        }
        
        return deserializationClass;
    }
}

然后实例化并配置解串器:

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

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

将其添加到模块中:

SimpleModule module = new SimpleModule("custom-deserializers", Version.unknownVersion());
module.addDeserializer(Animal.class, deserializer);

像往常一样注册模块并执行反序列化:

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

String json = "[{\"bark\":\"bowwow\"}, {\"bark\":\"woofWoof\"}, {\"meow\":\"meeeOwww\"}]";
List<Animal> animals = mapper.readValue(json, new TypeReference<List<Animal>>() { });

关于java - jackson 根据属性名称反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50460950/

相关文章:

java - ExecutorService 和 SwingWorker

python - 为什么我无法在 Python 中打印 JSON 属性?我究竟做错了什么?

java - 更改 Spring Boot 中的 application.yaml 以返回尽可能长的日期而不是时间戳

javascript - 将多个参数传递给 getJSON 会产生问题

javascript - 如何获取 .click 按钮来隐藏警报框

java - 如何使用 Jackson 更改 JSON 中的字段名称

java/jersey/jackson - 验证输入 JSON

java - 出现 mySQL 错误,未知列 where 子句

Javassist 和 Webstart

java - JAVA 中 URL 背后的逻辑