我正在尝试序列化泛型类的实例,同时保留泛型类型,因此我以后可以反序列化它,而不必手动指定泛型类型。
我理解反序列化通用对象的常用方法是使用类型引用或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
的所有出现的类型都是相同的(除了我想的一些多态情况)。
如果@JsonTypeInfo
省略otherStuff
注释,则杰克逊无法将otherStuff
的内容类型从value
类型中推迟。在此示例中,即使otherStuff
的类型为List<Integer>
,它也会将value
反序列化为BigDecimal
。
如何序列化泛型类的实例,以便以后可以安全地反序列化它们并保留泛型参数?
答案 0 :(得分:0)
类型信息确实需要包含在序列化的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
。