为什么左侧的类型被忽略 - 杰克逊反序列化

时间:2015-10-23 16:49:58

标签: java json jackson deserialization

我有这样的POJO

class POJO {
    Map<Integer, Integer> map;
    //Getter and Setter for map here
}

我有一个json(POJO列表)

[
    {
        "200": 10
    },
    {
        "20": 100,
        "30": 400
    }
]

杰克逊反序列化期间如果我这样做

String s = ... //s has the above json
List<POJO> pojoList = mapper.readValue(s, new TypeReference<List<POJO>>() {});
System.out.println(pojoList.get(0).getMap().get(20)); //prints 100

然后没有问题

但如果我使用像

那样的通用列表
List<POJO> pojoList = mapper.readValue(s, List.class);

然后在System.out.println投掷ClassCastException

java.util.LinkedHashMap cannot be cast to mycode.model.POJO

据我所知,如果我告诉杰克逊List,它会将每个对象反序列化为Map而不是类型POJO。因此,当我尝试访问pojoList.get(0).getMap()时,它会抛出异常

(注意:打印pojoList.get(0)没有问题,并打印{"200":10}

我的问题是为什么在反序列化过程中它不会抛出异常。 LHS上的对象类型是否被忽略了?

谢谢..

1 个答案:

答案 0 :(得分:2)

  

我的问题是为什么在反序列化期间它没有抛出异常   本身。 LHS上的对象类型是否被忽略了?

您对Java的工作方式存在误解。这两个语句的运行时评估

List<POJO> pojoList = mapper.readValue(s, List.class);
mapper.readValue(s, List.class);

完全一样。换句话说,指定的变量在运行时不起作用。在编译时,它的所有优点都可能为泛型和poly expressions提供上下文。

当您调用

mapper.readValue(s, List.class);

你告诉杰克逊将JSON反序列化为List。而已。你没有给它任何其他信息。杰克逊绝对没有办法猜测你是指POJO或其他任何东西的清单。因此,杰克逊猜测并使用自己的默认值。对于JSON对象,默认值为LinkedHashMap

此外,List.class评估为Class<List>,因此readValue的返回类型为原始List类型。使用原始类型时,将删除泛型。因此,您不会收到编译错误,但是您应该收到有关未选中转换的警告。

你应该阅读

另一方面,这个

List<POJO> pojoList = mapper.readValue(s, new TypeReference<List<POJO>>() {});

有效,因为您正在向Jackson所有正确反序列化JSON所需的信息。它是List(JSON数组)的POJO元素(JSON对象)。

然而,这有其自身的问题。 readValue的返回类型(即编译时间)是从上下文(我之前提到过)推断出来的,并绑定到List<POJO>,因为这是您将结果赋给的表达式的类型。 TypeReference在此处未提供泛型的类型信息。因此,您可以执行类似

的操作
List<String> stringList = mapper.readValue(s, new TypeReference<List<POJO>>() {}); 

它将编译没有错误。但在运行时,一切都可能会中断。