杰克逊解串器为通用类型

时间:2016-07-08 16:24:27

标签: java generics serialization jackson

我需要为具有泛型的类编写自定义反序列化程序。我找不到办法做到这一点,但我无法想象我是唯一有这个问题的人。据我所知,有两种方法可以实现,但没有一种方法可以实现:

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

    例如:

    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的实例时,没有可用的泛型参数的类型信息(类型擦除),因此它只选择最后一个反序列化器注册。

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

      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)并传递一个新的Module,其中包含一个FooDeserializer的实例。 class参数(我知道此时的类型)。 Module,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); 
      

      可能将其用于隐藏丑陋的实用方法。

2 个答案:

答案 0 :(得分:0)

我认为你不需要编写我们自己的自定义反序列化器。您可以使用此语法反序列化使用泛型的对象,这些对象取自另一个Stack Overflow线程。

mapper.readValue(jsonString, new TypeReference<Data<String>>() {});

情侣来源帮助您: Jackson - Deserialize using generic class http://www.tutorialspoint.com/jackson/jackson_data_binding_generics.htm

答案 1 :(得分:0)

您不需要编写自定义反序列化程序。通过将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。

请参阅Polymorphic DeserializationAnnotations上的杰克逊文档。