且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Jackson TypeReference在扩展时是否有效?

更新时间:2023-11-26 14:14:28

你需要了解一个 TypeReference 有效。为此,我们进入源代码

You need to understand how a TypeReference works. For that we go into the source code

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];
}

Class#getGenericSuperclass() javadoc states

The Class#getGenericSuperclass() javadoc states


返回表示实体
(类,接口,基本类型或void)的直接超类的Type )由本课程代表。

Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class.

如果超类是参数化类型,返回的$对象
必须准确反映源
代码中使用的实际类型参数。

If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code.

换句话说,如果我们可以做 new TypeReference()(我们可以' t,它是抽象的),它将为类 Object 返回 Class 实例。但是,使用匿名类(从类型扩展)

In other words, if we could do new TypeReference() (we can't, it's abstract), it would return the Class instance for the class Object. However, with anonymous classes (which extend from the type)

new TypeReference<String>(){}

创建的实例的直接超类是参数化类型 TypeReference 和根据javadoc,我们应该得到 Type 实例准确反映源代码中使用的实际类型参数

the direct superclass of the instance created is the parameterized type TypeReference and according to the javadoc we should get a Type instance that accurately reflect the actual type parameters used in the source code:

TypeReference<String>

然后您可以使用获取参数化类型getActualTypeArguments()[0 ]),返回字符串

from which you can then get the parameterized type with getActualTypeArguments()[0]), returning String.

让我们举一个例子来使用匿名类进行可视化并使用子类

Let's take an example to visualize using anonymous class and using a sub-class

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> 是源代码中的实际参数化类型。现在,如果相反,我们已经

which fits the javadoc rules. Test.AgentResponse<T> is the actual parameterized type in the source code. Now, if instead, we had

new Subclass<String>(){}; // anonymous inner class

我们得到的结果

Test.Subclass<java.lang.String>
class java.lang.String

这也适合账单。内部类现在直接从 Subclass 扩展,它在源代码中使用参数 String 进行参数化。

which also fits the bill. The inner class now extends directly from Subclass which is parameterized with the argument String in the source code.

您会注意到,使用 Subclass 匿名内部类,我们已经丢失了有关 AgentResponse的信息泛型类型。这是不可避免的。

You will notice that, with the Subclass anonymous inner class, we've lost information about the AgentResponse generic type. This is unavoidable.

请注意

reader = new StringReader("{\"element\":{\"map-element\":[{\"name\":\"soto\", \"value\": 123}]}}");
obj = mapper.readValue(reader, new AgentReq<Map<String, Set<Whatever>>>());

将编译并运行,但类型 AgentReq< Map< String,Set&lt ; Whatever>>> 将会丢失。 Jackson将使用默认类型来序列化JSON。 元素将被反序列化为 AgentResponse ,而 map-element 将被反序列化为 Map ,而JSON数组将被反序列为 ArrayList

will compile and run, but the type AgentReq<Map<String, Set<Whatever>>> will have been lost. Jackson will use default type to serializes the JSON. The element will be deserialized as an AgentResponse, while map-element will be deserialized as a Map and the JSON array as an ArrayList.