2017-10-10 28 views
0

我想在保留泛型类型的同时对泛型类的实例进行序列化,因此我将能够稍后反序列化它,而无需手动指定泛型类型。如何动态反序列化具有多个T的泛型类

据我所知,解串通用对象的常用方法是使用类型的引用或JavaType对象是这样的:

ObjectMapper om = new ObjectMapper(); 
ObjectReader or = om.reader(); 
ObjectWriter ow = om.writer(); 

String json = "[1, 2, 3]" 
JavaType listType = or.getTypeFactory() 
         .constructParametricType(List.class, Integer.class); 
List<Integer> integers = or.forType(listType).readValue(json) 

但我不知道(在这种情况下Integer)泛型类型事前,所以我不能这样做。

我也明白,由于删除,我必须以某种方式在序列化的JSON中包含类型信息。这可以通过@JsonTypeInfo注释来完成:

class Pojo<T> { 
    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 
    public T value; 
} 

然而,如果该类型T其他各种地方使用这个方法很快就会臃肿。考虑下面的例子:

class Pojo<T> { 
    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 
    public T value; 
    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 
    public List<T> otherStuff; 
    // constructor 
} 
// ... 
Pojo<BigDecimal> pojo = new Pojo<>(
    BigDecimal.valueOf(42), 
    Lists.newArrayList(BigDecimal.valueOf(14), BigDecimal.valueOf(23)) 
); 
final String json = ow.writeValueAsString(pojo); 
System.out.println(json); 

产生以下结果:

{ 
    "value": ["java.math.BigDecimal", 42], 
    "otherStuff":[ 
     ["java.math.BigDecimal", 14], 
     ["java.math.BigDecimal", 23] 
    ] 
} 

其重复的类型,在BigDecimal这种情况下,为每一个对象。这是不必要的,因为无论如何,T的所有发生类型都是相同的(除了在某些多态的情况下,我想)。

如果省略为otherStuff@JsonTypeInfo注释,杰克逊不能推迟的otherStuff内容从value类型的类型。在这个例子中,即使valueBigDecimal类型,它也会将otherStuff反序列化为List<Integer>

如何序列化泛型类的实例,以便我可以安全地反序列化它们并保留泛型参数?

回答

0

类型信息确实需要包含在序列化的json字符串中,但只有一次。我知道最简单的方法是编写使用@JsonCreator注释分两步进行反序列化的自定义创作者的方法:

  1. 让杰克逊反序列化所有非通用领域,而且包括类型信息的一个通用的领域。捕获其他通用字段为原始JsonNode,以便它们可以手动反序列化。
  2. 在运行时采取该类型的信息来反序列化剩余的字段。

对于上面的例子,这将如下所示(省略异常处理代码):

class Pojo<T> { 
    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 
    public T value; 
    public List<T> otherStuff; 
    // constructor 

    @JsonCreator 
    public static <T> Pojo<T> jsonCreator(
      @JsonProperty("value") T value, 
      @JsonProperty("otherStuff") JsonNode otherStuffRaw) { 
     JavaType listType = or.getTypeFactory() 
           .constructParametricType(List.class, value.getClass()); 
     return new Pojo<T>(
      value, 
      or.forType(listType).readValue(otherStuffRaw) 
     ); 
    } 
} 

然而,这允许value是的T一个子类,这可能会产生意外的结果。如果这是一个问题,另一种方法可能是使用Class<T>来保留T的确切类型。这也可以防止value可能是null

相关问题