您需要了解 a 的TypeReference
工作原理。为此,我们进入源代码
protected TypeReference()
{
Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class<?>) { // sanity check, should never happen
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
}
...
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
javadocClass#getGenericSuperclass()
状态
返回表示此 Class 所表示的实体(类、接口、原始类型或 void)的直接超类的 Type。
如果超类是参数化类型,则返回的 Type 对象必须准确反映源代码中使用的实际类型参数。
换句话说,如果我们能做new TypeReference()
(我们做不到,它是抽象的),它将返回Class
class 的实例Object
。但是,对于匿名类(从类型扩展)
new TypeReference<String>(){}
创建的实例的直接超类是参数化类型TypeReference
,根据 javadoc,我们应该得到一个准确反映源代码中使用的实际类型参数Type
的实例:
TypeReference<String>
然后您可以从中获取参数化类型getActualTypeArguments()[0])
,返回String
.
让我们举个例子来可视化使用匿名类和使用子类
public class Subclass<T> extends TypeReference<AgentResponse<T>>{
public Subclass() {
System.out.println(getClass().getGenericSuperclass());
System.out.println(((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
}
跑步
new Subclass<String>();
印刷
com.fasterxml.jackson.core.type.TypeReference<Test.AgentResponse<T>>
Test.AgentResponse<T>
这符合 javadoc 规则。Test.AgentResponse<T>
是源代码中的实际参数化类型。现在,如果相反,我们有
new Subclass<String>(){}; // anonymous inner class
我们得到结果
Test.Subclass<java.lang.String>
class java.lang.String
这也符合要求。内部类现在直接扩展,使用源代码中的Subclass
参数对其进行参数化。String
您会注意到,对于Subclass
匿名内部类,我们丢失了有关AgentResponse
泛型类型的信息。这是不可避免的。
注意
reader = new StringReader("{\"element\":{\"map-element\":[{\"name\":\"soto\", \"value\": 123}]}}");
obj = mapper.readValue(reader, new AgentReq<Map<String, Set<Whatever>>>());
将编译并运行,但类型AgentReq<Map<String, Set<Whatever>>>
将丢失。Jackson 将使用默认类型来序列化 JSON。将element
被反序列化为AgentResponse
,而JSON 数组map-element
将被反序列化为.Map
ArrayList