Jackson TypeReference在扩展时是否有效? [英] Does Jackson TypeReference work when extended?

查看:1544
本文介绍了Jackson TypeReference在扩展时是否有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码段是不言自明的。您可以看到类型信息未被删除,但mapper不会获取类型信息。我的猜测是杰克逊不允许这样,对吧?如果我直接传递TypeReference,它会被正确反序列化。

Following snippet is self-explanatory enough. You can see that type information is not erased, but mapper doesn't get the type information. My guess is that jackson doesn't allow this, right ? If I pass TypeReference directly, it is deserialized properly.

public class AgentReq<T> extends TypeReference<AgentResponse<T>> {...}

mapper.readValue(reader, new AgentReq<Map<String, Set<Whatever>>>());

如果我这样做,它也不起作用:

It also doesn't work if I do this :

public class AgentReq<T> {

    public TypeReference<AgentResponse<T>> getTypeRef() {
        return new TypeReference<AgentResponse<T>>() {};
    }
}

mapper.readValue(reader, new AgentReq<Map<String, Set<Whatever>>>()).getTypeRef();

我使用的是2.1.5版本。

I'm using version 2.1.5.

编辑:为了将来参考,在解决问题时不要低估TypeReference构造函数。在那里你可以直接看到它是否能够检索类型信息。顺便说一句答案是否定的,你不能扩展TypeReference并期望它工作,你甚至不能覆盖它的getType()方法并为它提供从你的类中解析的类型信息,因为你可以得到的只是getClass()。 getGenericSuperClass()...你不能做getClass()。getGenericClass()

For future reference, do not underestimate the TypeReference constructor when resolving problems. There you can see directly whether it was able to retrieve type information. Btw the answer is NO, you can't extend TypeReference and expect it to work, you can't even override its getType() method and supply it with type information resolved from your class, because all you can get is getClass().getGenericSuperClass() ... You can't do getClass().getGenericClass()

推荐答案

你需要了解一个 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< ; 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.

这篇关于Jackson TypeReference在扩展时是否有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆