如何将Java中JSON读取方法泛型化以适配任意对象?
问题描述
现有两个模型类:
class A{} class B{}
主调用代码如下:
public static void main(String[] args) throws IOException{ String aJson = "/tmp/a.json"; List<A> aList = readAJsonAsList(aJson); String bJson = "/tmp/b.json"; List<B> bList = readBJsonAsList(bJson); }
当前使用Jackson读取JSON文件,有两个分别针对A、B的读取方法:
// 针对A的方法 private static List<A> readAJsonAsList(String jsonAFile) throws IOException { ObjectMapper omA = new ObjectMapper(); List<A> aList = omA.readValue(new File(jsonAFile), new TypeReference<ArrayList<A>>() { }); return aList; } // 针对B的方法 private static List<B> readBJsonAsList(String jsonBFile) throws IOException { ObjectMapper omB = new ObjectMapper(); List<B> bList = omB.readValue(new File(jsonBFile), new TypeReference<ArrayList<B>>() { }); return bList; }
想把这两个方法合并为一个通用的Java泛型方法,但尝试的以下方法无法正常工作:
private static <T> List<T> readJsonAsList(String jsonFile) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); List<T> list = objectMapper.readValue(new File(jsonFile), new TypeReference<ArrayList<T>>() { }); return list; }
解决方案
你尝试的泛型方法失效的核心原因是Java泛型擦除机制:编译后TypeReference<ArrayList<T>>里的T会被替换成Object,Jackson无法识别实际要反序列化的目标类型,最终得到的是List<Object>而非期望的List<A>或List<B>。
要实现通用方法,需要显式传递目标类型的信息,有两种常用方案:
方案1:传入目标类的Class对象
通过TypeFactory构造CollectionType,明确指定列表元素的类型:
private static <T> List<T> readJsonAsList(String jsonFile, Class<T> elementType) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); // 构造List<T>的类型信息 CollectionType listType = objectMapper.getTypeFactory() .constructCollectionType(ArrayList.class, elementType); return objectMapper.readValue(new File(jsonFile), listType); }
调用方式:
List<A> aList = readJsonAsList("/tmp/a.json", A.class); List<B> bList = readJsonAsList("/tmp/b.json", B.class);
方案2:传入TypeReference对象
让调用方传递包含泛型信息的TypeReference,避免擦除问题:
private static <T> List<T> readJsonAsList(String jsonFile, TypeReference<List<T>> typeReference) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(new File(jsonFile), typeReference); }
调用方式:
List<A> aList = readJsonAsList("/tmp/a.json", new TypeReference<List<A>>() {}); List<B> bList = readJsonAsList("/tmp/b.json", new TypeReference<List<B>>() {});
额外优化:复用ObjectMapper
注意到你之前的方法每次都新建ObjectMapper,这是不必要的开销。ObjectMapper是线程安全的,建议全局复用一个实例:
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); // 对应方案1的优化版 private static <T> List<T> readJsonAsList(String jsonFile, Class<T> elementType) throws IOException { CollectionType listType = OBJECT_MAPPER.getTypeFactory() .constructCollectionType(ArrayList.class, elementType); return OBJECT_MAPPER.readValue(new File(jsonFile), listType); }
内容的提问来源于stack exchange,提问作者axnet
相关产品推荐
相关产品推荐

