有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何获取Jackson ObjectMapper的泛型类型

Java通常会在编译时擦除Generics数据,但也有可能获得该信息(Jackson ObjectMapper做得很好)

我的问题:我有一个属性为List的类:

public class User {
    public List<Long> listProp;//it is public only to keep the example simple
}

如何获得正确的TypeReference(或JavaType?)这样我就可以通过编程将JSON字符串映射到正确的列表类型,具有Class类(User.class)的实例和属性名(listProp)?我的意思是:

TypeReference typeReference = ...;//how to get the typeReference?
List<Long> correctList = om.readValue(jsonEntry.getValue(), typeReference);//this should return a List<Long> and not eg. a List<Integer>

共 (3) 个答案

  1. # 1 楼答案

    反序列化泛型类型的一种不太奇特的方法可能是将其包装在具体类型中:

    class ListLongWrapper extends ArrayList<Long> {} // package scope
    ... or ...
    static class ListLongWrapper extends ArrayList<Long> {} // class scope
    

    然后

    String jsonStr = objMapper.writeValueAsString(user1.listProp); // serialize
    user2.listProp = objMapper.readValue(jsonStr,ListLongWrapper.class); // deserialize
    

    注意extends需要类类型(这里我使用了ArrayList),而不是接口List


    这表明,对于给定示例,更直接的方法是User已经是一个包装器(而listProppublic):

    public class User {
        public List<Long> listProp;
    }
    

    然后

    String jsonStr = objMapper.writeValueAsString(user1); // serialize
    var user2 = objMapper.readValue(jsonStr,User.class); // deserialize
    

    在这种情况下,您可以使用接口List作为包装类中的字段类型,但这意味着您无法控制Jackson将使用的具体类型

  2. # 2 楼答案

    您尝试过mappers ConstructionType方法吗

    Type genericType = User.class.getField("listProp").getGenericType();
    List<Long> correctList = om.readValue(jsonEntry.getValue(), om.constructType(genericType));
    
  3. # 3 楼答案

    jackson使用TypeReference构造泛型类型

    TypeReference typeReference =new TypeReference<List<Long>>(){}
    

    jackson使用JavaType来构造泛型类型

    JavaType jt = om.getTypeFactory().constructArrayType(Long.class);
    

    jackson支持三种类型

    1. 阶级
    2. JavaType
    3. 类型引用

    我喜欢使用JavaType,对于泛型类型,对于普通的对象使用类,它更清晰