如何使用 Jackson 反序列化泛型 List<T>?

JDr*_*818 5 java class list type-erasure jackson

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

public static <T> TypeReference<List<T>> list() {
    return new TypeReference<List<T>>(){}
}
Run Code Online (Sandbox Code Playgroud)

预期用途:

List<Foo> foos = objectMapper.readValue(json, list());
Run Code Online (Sandbox Code Playgroud)

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

Jackson 和泛型类型引用

但是,为什么它能够分配List<LinkedHasMap>给 a List<Foo>?至少不应该是某种ClassCastException吗?

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

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

public static <T> TypeReference<List<T>> listOf(Class<T> ignored) {
    return new TypeReference<List<T>>(){}
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ber 12

由于Java 中的类型擦除,它的工作原理如下。请在开始阅读本答案的下一部分之前先阅读以下内容:

您现在可能知道,阅读完上述文章后,编译后的方法如下所示:

static <T> TypeReference<List> listOf(Class<T> ignored) {
    return new TypeReference<List>(){};
}
Run Code Online (Sandbox Code Playgroud)

Jackson 将尝试找出最适合它的java.util.LinkedHashMapJSON 对象类型。要创建无可辩驳的类型,您需要使用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
}
Run Code Online (Sandbox Code Playgroud)

上面的示例,对于以下JSON有效负载:

static <T> TypeReference<List> listOf(Class<T> ignored) {
    return new TypeReference<List>(){};
}
Run Code Online (Sandbox Code Playgroud)

印刷:

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
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: