以下摘录是不言而喻的。您可以看到类型信息没有被擦除,但是映射器没有得到类型信息。我的猜测是杰克逊不允许这样做,对吧?如果我直接传递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状态


返回表示实体的直接超类的Type
(由类表示)(类,接口,原始类型或void)。

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


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

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匿名内部类,我们已经丢失了有关AgentReq<Map<String, Set<Whatever>>>泛型类型的信息。这是不可避免的。



注意

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


将编译并运行,但是element类型将丢失。 Jackson将使用默认类型来序列化JSON。 AgentResponse将反序列化为map-element,而Map将反序列化为ArrayList,而JSON数组将反序列化为。

09-05 11:12