class java.util.LinkedHashMap cannot be cast to xxx
错误复现这个报错是在学习微服务的过程中发现的涉及到 Feign 远程调用。一共有两个服务user 和 user2。user 的 Feign 接口如下FeignClient(user) public interface UserClient { GetMapping(/user/getUser) Result getUser(RequestParam(id) int id); }接口实现如下GetMapping(/user/getUser) Override public Result getUser(int id) { return Result.success(new User(李华, 18)); }Result 是通用的返回类NoArgsConstructor AllArgsConstructor Data public class Result { private int status; private String msg; private Object data; public static Result success(Object data) { return new Result(1, null, data); } public static Result success() { return new Result(1, null, null); } }然后在 user2 服务中调用了 user 的 Feign 接口GetMapping(/user2/getUser) public Result getUser(int id) { Result result userClient.getUser(id); Object data result.getData(); User user (User) data; return Result.success(user); }结果就报错了在 User user (User) data 这里的强制类型转换错误了。这里我就不懂了Result.success(new User(李华, 18))Object data new User(李华, 18)从接口调用方得到的 data 也是 Oject 类型啊Object data result.getData()。不应该是 Object data new User(李华, 18)然后 User user (User) data这不是标准的向上转型和向下转型吗为什么这个时候把 Object 转成 User 就报错了呢原因分析问过 AI 才知道因为这个对象跨服务了。这个 User 对象从一个服务传输到了另一个服务那这个 User 对象是怎么传输过去的呢加了 RestController 注解User 对象就是被转成 JSON 字符串传输过去的然后被接口调用方从 JSON 解析得到 Result 对象。关键就在这里User 对象被转成了 JSON 字符串JSON 会记录这个 User 对象的类型吗并不会吧所以 JSON 被解析后再转成 User 对象就报错了。不对吧如果 JSON 不知道这个 User 对象的类型是怎么获取 User 的属性呢{status: 1, msg: null, data: {name: 李华, age: 18}}data 是 Object 类型啊如果不知道 data 是 User 类型怎么知道有 name 和 age 呢在 java 对象 - JSON 字符串的时候因为 data new User(李华, 18)框架中的 JSON 解析器可以通过反射获取 data 指向的 User 对象的属性所以这个接口返回的 JSON 字符串是包含 User 对象的 name 和 age 的。当这个 JSON 对象来到接口调用方的时候因为在 UserClient 中已经确定了 getUser 这个接口返回的就是 Result 对象所以 JSON 解析器会将 {status: 1, msg: null, data: {name: 李华, age: 18}} 这个字符串转成 Result 对象。这个 JSON 没有把 User 写在额头上吧所以 JSON 解析器会把 {name: 李华, age: 18} 转成 Object而不是转成 User 对象。但是呢JSON 解析器也不清楚 {name: 李华, age: 18} 到底是什么对象但是 JSON 都是键值对所以 JSON 解析器把 {name: 李华, age: 18} 转成了 LinkedHashMapString, Object 的对象也就是 Object data new LinkedHashMapString, Object()。User user (User) data 就是把 LinkedHashMap 对象转成 User 对象所以报错了提示class java.util.LinkedHashMap cannot be cast to class org.example.model.User。解决方案既然现在知道 data 是一个 LinkedHashMap 对象就可以解决问题了。方案一用 LinkedHashMap 的 API 获取 User 属性。GetMapping(/user2/getUser) public Result getUser(int id) { Result result userClient.getUser(id); Object data result.getData(); LinkedHashMapString, Object map (LinkedHashMapString, Object) data; User user new User(); String name (String) map.get(name); Integer age (Integer) map.get(age); user.setName(name); user.setAge(age); return Result.success(user); }方案二用 JSON 解析器转成 User 对象GetMapping(/user2/getUser) public Result getUser(int id) { Result result userClient.getUser(id); Object data result.getData(); ObjectMapper objectMapper new ObjectMapper(); User user objectMapper.convertValue(data, User.class); return Result.success(user); }泛型尝试原来这个报错是因为 JSON 转对象的时候不知道类型啊那我把 Result 的 data 改成泛型不就行了吗好吧进行一下泛型的尝试NoArgsConstructor AllArgsConstructor Data public class ResultT { private int status; private String msg; private T data; public static T ResultT success(T data) { return new Result(1, null, data); } public static Result success() { return new Result(1, null, null); } }如果只改 Result 的话还是会报错的因为你没改接口。接口返回的还是 Result没有指定返回值的类型。java 是有泛型擦除的所以接口调用方还是会把 JSON 字符串转成 Result 对象把 data 字符串转成 LinkedHashMap令 data LinkedHashMap 对象强转还是报错。需要手动指定返回值的类型才可以自动转换GetMapping(/user/getUser) ResultUser getUser(RequestParam(id) int id);GetMapping(/user2/getUser) public ResultUser getUser(int id) { ResultUser result userClient.getUser(id); User user result.getData(); return Result.success(user); }现在直接获取到的就是 User 对象了JSON 解析器在底层已经帮你完成转换流程了。泛型不是会被擦除吗怎么这里又知道是 User 类型了泛型确实会被擦除啊但是接口方法都写明了返回的是一个 User 类对象ResultUser result userClient.getUser(id)JSON 解析器就知道了要把 data 转成 User 对象。那我如果不需要在 Result 对象中设置 data 呢那就让 data 等于 null 就可以了。public static T ResultT success() { return new Result(1, null, null); }Controller 层的接口返回 ResultVoid 表示这个接口没有 dataJSON 字符串中 data 为 null。GetMapping(/void-test) public ResultVoid voidTest() { return Result.success(); }{ status: 1, msg: null, data: null }