Gson反序列化时LinkedTreeMap强转OrderProfile报ClassCastException异常
异常根因
你没有主动存入LinkedTreeMap,这个对象是Gson反序列化流程自动生成的:
- 你的
extras字段声明为Map<String, Object>,Java泛型存在类型擦除,Gson反序列化这个Map的时候,只知道值是Object类型,无法识别orderProfile键对应的值实际是OrderProfile自定义类,就会默认把嵌套的JSON对象解析成内部用的LinkedTreeMap键值对结构存入Map,根本不会还原成你之前存入的OrderProfile实例。 - 异常中提示两个类属于不同
URLClassLoader实例,常见于插件热加载、模块化隔离的运行环境,属于衍生问题,核心触发点是你取出的对象本身就不是OrderProfile类型。
注意:如果你的运行环境存在插件/模块热重载逻辑,就算对象类型正确,不同类加载器加载的同全限定名类也无法互转,需要在重载时清空旧缓存、重新加载用户数据。
修复方案
你可以根据自己的业务场景选以下任意一种方案:
- 方案1:兼容现有逻辑,在取值时做二次转换
直接修改OrderProfile.get()方法,兼容Gson生成的LinkedTreeMap场景,转换完成后把正确类型的对象回写到Map里,避免重复转换:public static OrderProfile get(@NotNull User user) { Map<String, Object> extras = user.getExtras(); Object rawValue = extras.get("orderProfile"); if (rawValue == null) { return null; } // 已经是正确类型直接返回 if (rawValue instanceof OrderProfile) { return (OrderProfile) rawValue; } // 处理Gson反序列化生成的LinkedTreeMap if (rawValue instanceof Map) { Gson gson = new Gson(); OrderProfile profile = gson.fromJson(gson.toJson(rawValue), OrderProfile.class); extras.put("orderProfile", profile); return profile; } return null; } - 方案2:把固定业务字段从extrasMap中提升为User的正式字段
对于orderProfile这类固定存在的业务属性,不要放在无类型的extrasMap里存储,直接声明为User的成员字段,Gson反序列化时能直接识别字段类型,不会生成LinkedTreeMap:@AllArgsConstructor public class User { private Map<String, Object> extras; // 直接声明固定业务字段 private OrderProfile orderProfile; // other fields public Map<String, Object> getExtras() { if (extras == null) extras = new HashMap<>(); return extras; } public OrderProfile getOrderProfile() { return orderProfile; } } - 方案3:自定义Gson反序列化逻辑
如果必须保留Map<String, Object>的extras结构,可以给Gson实例注册自定义的TypeAdapter,反序列化extrasMap时,识别orderProfile这类特殊key,直接把对应JSON反序列化为OrderProfile类型,从根源避免生成LinkedTreeMap。
内容的提问来源于stack exchange,提问作者ananoun
相关产品推荐
相关产品推荐

