侧边栏壁纸
  • 累计撰写 94 篇文章
  • 累计创建 100 个标签
  • 累计收到 10 条评论

目 录CONTENT

文章目录

Jackson解析集合的问题分析

汤圆学Java
2022-02-18 / 0 评论 / 0 点赞 / 251 阅读 / 2,740 字
温馨提示:
本文最后更新于 2022-02-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

Jackson解析集合其实跟解析Java对象是一样的,只是稍微有点不同;

如果集合内的数据类型是基本类型,比如String这样的,那么我们可以直接解析,readValue(s, List.class),输出也不会有问题;

但是如果集合内的数据类型是Java类,比如User这样的,那么解析就会出问题,因为Jackson会擦除类的信息,输出Map这样的数据;

下面我们用例子来看下;

目录

  1. 解析基本类型的集合
  2. 解析Java类的集合

正文

1. 解析基本类型的集合

这个直接看代码就可以了,如下所示:

List<String> list = Arrays.asList("a","b");
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(list);

List<String> list1 = objectMapper.readValue(s, List.class);
System.out.println(list1);

输出如下:

image-20220216182247831

可以看到,符合预期,没有异议;

2. 解析Java类的集合

这里我们创建一个User实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private String username;

    private String password;

}

然后主程序构建多个User对象进行测试:

User user = new User("jalon", "xiaowang");
User user2 = new User("jalon2", "xiaowang2");
List<User> list = Arrays.asList(user, user2);
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(list);

List<User> list1 = objectMapper.readValue(s, List.class);
System.out.println( list1.get(0).getUsername());

这里我们想要显示第一个User的username,但是运行却报错:

image-20220216182954329

问题描述:

错误提示说LinkedHashMap不能转为User,说明此时解析的列表中的User类属性信息被擦除了,取而代之的是LinkedHashMap;

解决办法:

这里的解决办法有两种,构造TypeReference和CollectionType,这两种办法的核心都是将待序列化的集合包装起来,然后进行相应的处理;

办法1:TypeReference包装器

TypeReference接收一个泛型T作为形参,我们可以把List<User>作为实参传进去,然后再读取TypeReference类型的数据,代码如下:

TypeReference<List<User>> typeReference = new TypeReference<List<User>>() {};
List<User> list1 = objectMapper.readValue(s, typeReference);

这里的readValue内部是将TypeReference转为JavaType进行处理的,源码如下:

image-20220217111610106

可以看到,本质上是通过typeReference参数构造了一个JavaType

这时我们再运行输出如下:

image-20220217111729055

可以看到,成功访问到了User.username属性,如果打印整个List,会输出所有的User对象:

System.out.println( list1);

image-20220217111823723

办法2:CollectionType包装器

这个CollectionType包装器是将List集合和User实体类的属性分开包装,然后再进行读取操作,如下所示:

CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, User.class);
List<User> list = objectMapper.readValue(s, collectionType);

此时再运行输出,跟上面一样的结果,都是正常输出;

不管是这里的CollectionType包装器,还是上面的TypeReference包装器,核心都是包装 待序列化的集合和元素类型,然后在读取操作时进行相应的转换处理;

总结

如果解析的集合元素是基本类型,那么直接解析即可,不用做任何处理;

如果解析的集合元素是Java类,那么需要用TypeReference或CollectionType对集合进行包裹,然后再进行读取操作;

0

评论区