为什么Jackson的ObjectMapper方法采用原始的TypeReference(Why Jackson’s ObjectMapper methods take raw TypeReference)
Jackson 2
ObjectMapper
类定义了许多用于将JSON字符串,字节数组,文件等反序列化为给定Java类型的通用方法。目标类型在这些方法的参数中给出。
例如。 类型可以作为
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)
实际上采用了一个完全限定的泛型参数 :public <T> T readValue(JsonParser p, TypeReference<T> valueTypeRef)
Jackson 2
ObjectMapper
class defines numerous generic methods for deserializing JSON strings, byte arrays, files, etc. to given Java types.Target type is given in an argument to those methods.
Eg. a type may be given as a
Class<T>
, like in the methodpublic <T> T readValue(String content, Class<T> valueType)
which returns the same
T
object (and thus is type-safe to use).But it may also be given as a
TypeReference<T>
(which can encode a complex generic type), so one can build eg.new TypeReference<List<Long>> { }
to tellObjectMapper
that the input needs to be deserialized into a list of longs – it can be passed eg. into the method:@SuppressWarnings({ "unchecked", "rawtypes" }) public <T> T readValue(String content, TypeReference valueTypeRef)
But that method takes raw
TypeReference
and not a genericTypeReference<T>
, and thus one needs to manually add a generic parameter to the call:objectMapper.<List<Long>>readValue(input, listOfLongs)
and if one makes a mistake in the provided type, the compiler cannot catch that. That would not be a problem if the method signature was
public <T> T readValue(String content, TypeReference<T> valueTypeRef)
which would tell the compiler that the returned value is always of the same type as the generic parameter of provided
TypeReference
, similarly to how it works withClass<T>
.My question is – what is the reason behind such an API? Why do Jackson methods take raw
TypeReference
? Are there any valid cases when returned object is really of a different type that that referenced by generic parameter ofTypeReference
?PS: What also puzzles me is that a corresponding
convertValue
method takes not a raw type, but a wildcard one:public <T> T convertValue(Object fromValue, TypeReference<?> toValueTypeRef)
and similarly
readValues
:public <T> MappingIterator<T> readValues(JsonParser p, TypeReference<?> valueTypeRef)
and the
readValue(JsonParser, TypeReference)
actually takes a fully qualified generic parameter:public <T> T readValue(JsonParser p, TypeReference<T> valueTypeRef)
原文:https://stackoverflow.com/questions/48401520
最满意答案
它已被报告为一个问题 ,但被标记为
3.x
图书馆的作者发表了一条评论,解释了为什么还没有纠正这个问题:
看起来像
ObjectMapper
API(也可能是ObjectReader
)省略了与TypeReference
类型变量匹配。 这对改变是有意义的,但可能会导致一些源兼容性问题(不是二进制),所以也许在3.0而不是更早的时候这样做。It is already reported as an issue, but was labeled as
3.x
.There's a comment by the author of the library that explains why this hasn't been corrected yet:
Looks like
ObjectMapper
API (and perhapsObjectReader
too) omits type-variable matching withTypeReference
. 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.
相关问答
更多-
Java有一种称为类型擦除的东西。 这意味着,一旦编译,你的 List
listOfObjects = new ArrayList (); 变 List listOfObjects = new ArrayList(); 因此,一旦运行你的程序,杰克逊就无法判断你是否期望返回myObject的列表。 相反,它返回LinkedHashMap的列表。 通过创建扩展TypeReference的内部类,您迫使Java保留您期望myObject类型列表的事实。 请参阅此处以获取 ... -
其他原因是ObjectMapper的每个实例都绑定了ObjectMapper准备好的特定配置,而序列化和反序列化过程类似于下面的内容。 因此,您可以在对象转换过程中配置不同的startegies。 ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); String json = mapper.writ ...
-
如何使用ObjectMapper Jackson反序列化泛型类型(How to deserialize a generic type with ObjectMapper Jackson)[2022-09-14]
我终于想出了一个解决方案,这里是: public staticList getList(String url, Class clazz) { HttpClient client = HttpClientBuilder.create().build(); HttpGet getRequest = new HttpGet(url); getRequest.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSO ... -
问题 :您在JsonObjectRequest上缺少Method.GET和JSONObject jsonObject参数 这是构造函数,注意第一个和第三个参数。 public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener
listener, ErrorListener errorListener) 或者,也是这个 public JsonObjectRequest( ... -
当然是。 否则,数组和列表将不再是数组和列表。 测试一下,亲自看看。 这可能是一种更快捷的方式,但它可能不会那么方便,而且你这样做的方式可能足够快。 除非您的阵列中有数百万个ID,否则我怀疑用户会发现此解决方案与更快的解决方案之间存在任何差异。 过早优化是万恶之源。 不要试图优化不需要的东西。 Yes, of course. Otherwise, an array and a list wouldn't be an array and a list anymore. Test it, and see by ...
-
为什么Jackson的ObjectMapper方法采用原始的TypeReference(Why Jackson’s ObjectMapper methods take raw TypeReference)[2023-01-23]
它已被报告为一个问题 ,但被标记为3.x 图书馆的作者发表了一条评论,解释了为什么还没有纠正这个问题: 看起来像ObjectMapper API(也可能是ObjectReader )省略了与TypeReference类型变量匹配。 这对改变是有意义的,但可能会导致一些源兼容性问题(不是二进制),所以也许在3.0而不是更早的时候这样做。 It is already reported as an issue, but was labeled as 3.x. There's a comment by the au ... -
如何获取Jackson ObjectMapper的Generic类型(How to get the Generic type for the Jackson ObjectMapper)[2022-04-06]
你试过过mappers constructType方法吗? Type genericType = User.class.getField("listProp").getGenericType(); ListcorrectList = om.readValue(jsonEntry.getValue(), om.constructType(genericType)); Have you tried the mappers constructType method? Type genericTyp ... -
问题在于输入TypeReference。 我正在使用 import com.fasterxml.jackson.core.type.TypeReference 代替 import org.codehaus.jackson.type.TypeReference Issue was with import of TypeReference. I was using import com.fasterxml.jackson.core.type.TypeReference instead of import org ...
-
如何使用jackson ObjectMapper将POJO映射到自定义地图?(How to map a POJO to a custom Map using jackson ObjectMapper?)[2022-01-02]
我最后提出了以下解决方案: public class Document extends LinkedHashMapimplements Serializable { } public class JacksonMapper { private ObjectMapper objectMapper; public Document asDocument(T object) { ObjectMapper objectMapper = g ... -
您需要了解TypeReference工作原理。 为此,我们进入源代码 protected TypeReference() { Type superClass = getClass().getGenericSuperclass(); if (superClass instanceof Class>) { // sanity check, should never happen throw new IllegalArgumentException("Internal erro ...