如何动态反序列化具有多个T的泛型类
问题描述:
我想在保留泛型类型的同时对泛型类的实例进行序列化,因此我将能够稍后反序列化它,而无需手动指定泛型类型。如何动态反序列化具有多个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
类型的类型。在这个例子中,即使value
是BigDecimal
类型,它也会将otherStuff
反序列化为List<Integer>
。
如何序列化泛型类的实例,以便我可以安全地反序列化它们并保留泛型参数?
答
类型信息确实需要包含在序列化的json字符串中,但只有一次。我知道最简单的方法是编写使用@JsonCreator
注释分两步进行反序列化的自定义创作者的方法:
- 让杰克逊反序列化所有非通用领域,而且包括类型信息的一个通用的领域。捕获其他通用字段为原始
JsonNode
,以便它们可以手动反序列化。 - 在运行时采取该类型的信息来反序列化剩余的字段。
对于上面的例子,这将如下所示(省略异常处理代码):
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
。