java - Jackson TypeReference 在扩展时是否有效?

标签 java json jackson

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

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

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

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

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 版。

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

最佳答案

您需要了解 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];
}

Class#getGenericSuperclass() javadoc 状态

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() (我们不能,它是抽象的),它会返回 Class类的实例 Object .但是,对于匿名类(从类型扩展)

new TypeReference<String>(){}

创建的实例的直接父类(super class)是参数化类型TypeReference根据 javadoc 我们应该得到一个 Type 准确反射(reflect)源代码中使用的实际类型参数的实例:

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 , 而 map-element将被反序列化为 Map和 JSON 数组作为 ArrayList .

关于java - Jackson TypeReference 在扩展时是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19283606/

相关文章:

java - Bean 验证@ElementCollection 和@Version 冲突并验证失败

python - 将目录中的所有文件加载为名为正在加载的文件名的变量?

json - 在 Golang 中完全解析时间戳

javascript - PHP 未收到 Ajax 发送的 JSON

java - Java中获取多个网页最快的方法

java - Java android studio 项目中的NoFileFoundException

java.io.IOException : Premature EOF

java - spring.jackson.date-format 属性对于使用 @Temporal 注释的日期序列化无法正常工作

java - Spring Boot Rest Controller 中与 Jackson @JsonIgnore 合作 MongoDB 延迟加载

java - Spring转义已经转义的字符串