前言
Jackson解析集合其实跟解析Java对象是一样的,只是稍微有点不同;
如果集合内的数据类型是基本类型,比如String这样的,那么我们可以直接解析,readValue(s, List.class)
,输出也不会有问题;
但是如果集合内的数据类型是Java类,比如User这样的,那么解析就会出问题,因为Jackson会擦除类的信息,输出Map这样的数据;
下面我们用例子来看下;
目录
- 解析基本类型的集合
- 解析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);
输出如下:
可以看到,符合预期,没有异议;
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,但是运行却报错:
问题描述:
错误提示说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进行处理的,源码如下:
可以看到,本质上是通过typeReference参数构造了一个JavaType
这时我们再运行输出如下:
可以看到,成功访问到了User.username属性,如果打印整个List,会输出所有的User对象:
System.out.println( list1);
办法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对集合进行包裹,然后再进行读取操作;
评论区