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

Why Jackson’s ObjectMapper methods take raw TypeReference

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

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

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

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

哪个 returns 相同的 T 对象(因此使用类型安全)。

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

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

但该方法采用 raw 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)

TypeReference 摘要 class 并不意味着直接用作通用信息的容器。这是来自 javadoc:

This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" bundle) to be used.

即使 ObjectMapper 接受了一个参数化的 TypeReference ,它也不会完成这项工作,因为像 new TypeReference<List<Long>> { } 这样的所有通用规范在 运行 时被完全删除。

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

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

然后

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

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

库的作者有一条评论解释了为什么这个问题还没有得到更正:

Looks like ObjectMapper API (and perhaps ObjectReader too) omits type-variable matching with TypeReference. This would make sense to change, but is likely to cause some source-compatibility issues (not binary), so perhaps do this in 3.0 and not earlier.