【问题标题】:How to deserialize generic List<T> with Jackson?如何用 Jackson 反序列化泛型 List<T>?
【发布时间】:2020-07-23 19:51:00
【问题描述】:

多年来,我一直在使用 Jackson 序列化/反序列化对象,并且一直发现使用 TypeReference&lt;T&gt; 反序列化 List 等不必要地复杂。我创建了一个简单的辅助函数:

public static <T> TypeReference<List<T>> list() {
    return new TypeReference<List<T>>(){}
}

按预期用途:

List<Foo> foos = objectMapper.readValue(json, list());

而且它有效!的种类。通过调试器检查时,而不是Foo 的列表,而是LinkedHashMap 的列表。我知道ObjectMapper 反序列化为LinkedHashMap 类型为Object,我在这里阅读了解释:

Jackson and generic type reference

但是,为什么它能够将List&lt;LinkedHasMap&gt; 分配给List&lt;Foo&gt;?至少不应该是某种ClassCastException

另外,有没有办法用 Java 的类型系统做到这一点?

注意:以下方法声明具有相同的问题,这是有道理的,因为确定 T 不需要额外的参数:

public static <T> TypeReference<List<T>> listOf(Class<T> ignored) {
    return new TypeReference<List<T>>(){}
}

【问题讨论】:

标签: java list class jackson type-erasure


【解决方案1】:

由于Java 中的类型擦除,它的工作原理是这样的。请在开始阅读此答案的下一部分之前阅读它:

你现在可能知道,看完上面的文章,你编译后的方法是这样的:

static <T> TypeReference<List> listOf(Class<T> ignored) {
    return new TypeReference<List>(){};
}

Jackson 将尝试找出最适合它的类型,即java.util.LinkedHashMap 对应JSON Object。要创建 无可辩驳 type,您需要使用 com.fasterxml.jackson.databind.type.TypeFactory 类。见下例:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;

import java.io.File;
import java.util.List;

public class JsonTypeApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();

        System.out.println("Try with 'TypeFactory'");
        List<Id> ids = mapper.readValue(jsonFile, CollectionsTypeFactory.listOf(Id.class));
        System.out.println(ids);
        Id id1 = ids.get(0);
        System.out.println(id1);

        System.out.println("Try with 'TypeReference<List<T>>'");
        List<Id> maps = mapper.readValue(jsonFile, CollectionsTypeFactory.erasedListOf(Id.class));
        System.out.println(maps);
        Id maps1 = maps.get(0);
        System.out.println(maps1);
    }
}

class CollectionsTypeFactory {
    static JavaType listOf(Class clazz) {
        return TypeFactory.defaultInstance().constructCollectionType(List.class, clazz);
    }

    static <T> TypeReference<List> erasedListOf(Class<T> ignored) {
        return new TypeReference<List>(){};
    }
}

class Id {
    private int id;

    // getters, setters, toString
}

上面的例子,下面的JSON有效载荷:

[
  {
    "id": 1
  },
  {
    "id": 22
  },
  {
    "id": 333
  }
]

打印:

Try with 'TypeFactory'
[{1}, {22}, {333}]
{1}
Try with 'TypeReference<List<T>>'
[{id=1}, {id=22}, {id=333}]
Exception in thread "main" java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.example.Id
    at com.example.JsonTypeApp.main(JsonTypeApp.java:27)

另见:

【讨论】:

  • 文章真的很有帮助。谢谢!
猜你喜欢
  • 2014-04-05
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多