【实战问题】【15】报错java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to xx
场景重现:调用封装好的接口,返回的数据类型是 List,debug 可以看到有返回值。但是进行到对 list 进行操作的那步,报错了(java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to xx)。原来 list 中的数据是 LinkedTreeMap 格式的,并没有转换成对应的实体类。网上查的方法很多是解决 json 格式字符串转成实体类,而我因为接收到的就是 List 数据,所以还是想转成能使用的 List 数据。
写在前面:尝试多种方法没有解决问题,最终是改了封装的接口,数据格式从源头就错了
原因:泛型 <T> 不能强转为 List,会有一系列问题
排查历程:
(1)最开始我的代码
获取到了 List,取出状态有效的数据。如此简单,开心。
//主要代码 List<UserEntity> userList = this.commentService.getUserList(userId); //获取数据的接口 List<UserEntity> newList = list.stream().filter(i -> i.getStatus() == 1).collect(Collectors.toList()); //报错
然后就报错了,返回的数据格式是这样的:
(2)在网上查这个报错,试了 gson 转 list,没用
Gson gson = new GsonBuilder().create();//想着把 list 的值转成 json 格式的字符串
String userJson= gson.toJson(userList);//方式 1
T[] array = gson.fromJson(userJson, UserEntity.class);
List<UserEntity> newList = Arrays.asList(array);//方式 2
List<UserEntity> list = (List<UserEntity>) gson.fromJson(userJson, new TypeToken<List<UserEntity>>(){}.getType());
(3)用 ObjectMapper 转,有用,但是数据格式匹配不上,报错。实体类中是 Integer 的值,在 LinkedTreeMap 中是 Double 了。
ObjectMapper mapper = new ObjectMapper(); List<UserEntity> list = mapper.convertValue(userList, new TypeReference<List<UserEntity>>(){});
//userList 这里有点记不清了,不记得有没有用 userJson。TODO
(4)用 Map 承接 userList.get(0),再处理数据。可行,但是我还要做条件筛选,这个做不到我的需求
Map map = userList.get(0); UserEntity newInfo = new UserEntity (); newInfo.setName(map.get("name").toString()); ... //用 for 循环会报错。。。
(5)从源头解决问题
封装的接口里的 List 转换有问题
List<UserEntity> list = (List<UserEntity>) this.restClient.get(url, List.class); //这是调用了远程接口,restClient 是封装了 get,post 通用方法,所以不能改,返回值本来是 <T>
更改后:
JsonArray json= this.restClient.get(url, JsonArray.class); List<UserEntity> list = gson.fromJson(json, new TypeToken<List<UserEntity>>(){}.getType());