2017-10-10 87 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