java - 用于泛型类型的 Jackson 反序列化器

标签 java generics serialization jackson

我需要为带有泛型的类编写一个自定义反序列化器。我找不到一种方法来做到这一点,但我无法想象我是唯一遇到这个问题的人。据我思考,有两种方法可以实现这一点,但都无法实现:

  1. 在反序列化器的构造函数中向反序列化器提供 Class 参数不起作用,因为在注册反序列化器时,Type.class 和反序列化器实例与传递的 Class 实例之间的关系会丢失。

例如:

public class Foo<T> {}
public class FooDeserializer<T> {
    public FooDeserializer(Class<T> type) { ... }
    ...
}
// Boilerplate code...
module.addDeserializer(Foo.class, new FooDeserializer<Bar1>(Bar1.class));
module.addDeserializer(Foo.class, new FooDeserializer<Bar2>(Bar2.class));

这是行不通的,当 ObjectMapper 实例获取 Foo 的实例时,没有可用的泛型参数的类型信息(类型删除),因此它只是选择最后注册的反序列化器。

  • 在类中保留泛型类型的引用没有帮助,因为类的实例化版本无法传递给反序列化器(接口(interface)为 readValue(String, Class))。
  • 例如:

    String json = "...";
    ObjectMapper mapper = ...;
    Foo<Bar1> foo = new Foo<>(Bar1.class);
    foo = mapper.readValue(json, Foo.class); // Can't pass empty foo instance with Class<?> field containing Bar1.class
    

    需要这样的东西:

    mapper.readValue(json, Foo.class, Bar1.class); // Doesn't exist in jackson
    

    有什么建议吗?

    编辑: 我找到了解决问题的方法,但这不是一个干净的解决方案:

    我使用 Class 字段扩展 FooDeserializer,以保存 Foo 泛型参数的类型。然后,每次我想将一些 json 反序列化到一个新的 Foo 实例中时,我都会得到一个新的 ObjectMapper 实例(我在工厂中的预配置实例上使用 ObjectMapper#copy )并向其传递一个新模块,其中包含 FooDeserializer 的实例类参数(我此时知道类型)。模块、FooDeserializer 和 ObjectMapper 副本都是短暂的,它们仅针对此单个反序列化操作进行实例化。正如我所说,不是很干净,但仍然比多次子类化 Foo 并为每个子类编写一个反序列化器要好。

    示例:

    public class FooDeserializer<T> extends StdDeserializer<T> {
        private Class<T> type;
        public FooDeserializer(Class<T> type) { this.type = type }
        ...
    }
    
    // Meanwhile, before deserialization:
    ObjectMapper mapper = MyObjectMapperFactory.get().copy();
    SimpleModule module = new SimpleModule(new Version(0,0,1,null,null,null);
    module.addDeserializer(Foo.class, new FooDeserializer(Bar1.class);
    mapper.addModule(module);
    Foo<Bar1> x = mapper.readValue(json, Foo.class); 
    

    可能将其放入实用方法中以隐藏丑陋之处。

    最佳答案

    您不需要编写自定义反序列化器。可以通过在作为参数传递给泛型类的类型上放置 Jackson 注释来反序列化泛型。
    注释类Bar1如下:

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
    @JsonTypeName("Bar1")
    class Bar1 {
    
    }
    

    现在,当您反序列化 Foo<Bar1> 的实例时,Jackson 会将类型参数信息放入 JSON 中。然后可以将此 JSON 反序列化为通用类 Foo.class就像反序列化任何其他类一样。

    ObjectMapper mapper = ...;
    Foo<Bar1> foo = new Foo<Bar1>();
    String json = objectMapper.writeValueAsString(foo);
    foo = mapper.readValue(json, Foo.class); // no need to specify the type Bar1.
    

    因此,如果每个可以作为参数传递给 Foo 的类都带有注释,那么可以在编译时不知道参数类型的情况下反序列化 JSON。

    请参阅 Jackson 文档 Polymorphic DeserializationAnnotations .

    关于java - 用于泛型类型的 Jackson 反序列化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38271440/

    相关文章:

    java - JPA 2.0未在myEclipse Professional 2013中显示架构中的表

    java -/Library/Java/Extensions 的作用是什么 - 从那里添加或删除类是否安全?

    java - 这是内存泄漏吗?

    java修剪通用数组

    c# - 为什么是 IEnumerable.Empty<T>() 而不是 IEnumerable<T>.Empty()?

    java - 两个数组的交集(索引越界异常)

    go - 使用外部包中的公共(public)成员处理不同结构的通用函数?

    mysql - 将 Django 模型数据导出为 MySQL 文件?

    c++ - 序列化具有不同成员的继承类 MFC c++

    json - RestSharp:如何跳过将空值序列化为 JSON?