为什么Jackson的ObjectMapper方法采用原始TypeReference

时间:2018-01-23 12:16:17

标签: java generics jackson jackson2

Jackson 2 ObjectMapper类定义了许多用于将JSON字符串,字节数组,文件等反序列化为给定Java类型的通用方法。

目标类型在这些方法的参数中给出。

EG。类型可以作为Class<T>给出,就像方法

一样
public <T> T readValue(String content, Class<T> valueType)

返回相同的T对象(因此可以使用类型安全)。

但它也可以作为TypeReference<T>(可以编码复杂的泛型类型)给出,因此可以构建例如。 new TypeReference<List<Long>> { }告诉ObjectMapper需要将输入反序列化为longs列表 - 例如,可以传递它。进入方法:

@SuppressWarnings({ "unchecked", "rawtypes" })
public <T> T readValue(String content, TypeReference valueTypeRef)

但该方法需要原始 TypeReference而非通用TypeReference<T>,因此需要手动为调用添加通用参数:

objectMapper.<List<Long>>readValue(input, listOfLongs)

如果在提供的类型中出错,编译器就无法捕获它。如果方法签名是

,这不会有问题
public <T> T readValue(String content, TypeReference<T> valueTypeRef)

这将告诉编译器返回的值始终与提供的TypeReference的泛型参数的类型相同,类似于它与Class<T>的工作方式。

我的问题是 - 这样的API背后的原因是什么?为什么Jackson方法采用原始TypeReference?当返回的对象实际上是由TypeReference的泛型参数引用的不同类型时,是否存在任何有效情况?

PS:还有什么让我感到困惑的是,相应的convertValue方法不是原始类型,而是通配符:

public <T> T convertValue(Object fromValue, TypeReference<?> toValueTypeRef)

,同样readValues

public <T> MappingIterator<T> readValues(JsonParser p, TypeReference<?> valueTypeRef)

readValue(JsonParser, TypeReference)实际上takes a fully qualified generic parameter

public <T> T readValue(JsonParser p, TypeReference<T> valueTypeRef)

2 个答案:

答案 0 :(得分:3)

已经reported as an issue,但标记为3.x

图书馆的作者发表了一篇评论,解释了为什么还没有纠正这个问题:

  

看起来ObjectMapper API(也可能是ObjectReader)省略了与TypeReference匹配的类型变量。这对改变是有意义的,但很可能会导致一些源兼容性问题(不是二进制),所以可能在3.0而不是更早的时候这样做。

答案 1 :(得分:-1)

TypeReference抽象类不能直接用作通用信息的容器。这来自javadoc

  

此通用抽象类用于获取完整的泛型类型   分类信息;它必须转换为ResolvedType   实现(由来自&#34; databind&#34; bundle的JavaType实现)   使用

即使ObjectMapper接受了参数化TypeReference,它也无法完成工作,因为所有通用规范(如new TypeReference<List<Long>> { })都会在运行时完全删除。

要将通用信息传递给杰克逊的ObjectMapper,您需要创建一个JavaType个实例:

JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, Long.class);

然后

List<Long> list = mapper.readValue(..., type);