【Feign远程调用异常】解决java.util.LinkedHashMap cannot be cast to 实体类......的问题

解决java.util.LinkedHashMap cannot be cast to 实体类…的问题
背景描述
在写微服务项目黑马商城的时候,在搜索服务的测试类通过feign的接口客户端远程调用商品服务接口的时候,搜索服务测试类方法中得到的返回的值PageDTO类对象中的List<Item>对象遍历后居然不是Item,而是LinkedHashMap,可知远程调用会将待转换的数据转换成LinkedHashMap,而将其转换成想要的数据类型,肯定行不通,会报上面的异常。

参考网友的博客并得到解决,说是使用RestTemplate远程调用的时候出现的类似问题。但我并没有使用RestTemplate,不过也解决了,解决方式如下:

            List<Item> remoteList = pageDTO.getList();
            String jsonStr = JSON.toJSONString(remoteList);//依旧使用alibaba提供的json转换工具,需要fastjson依赖
            List<Item> items = JSONObject.parseArray(jsonStr, Item.class);

            for (Item item : items) {
                ItemDoc itemDoc = new ItemDoc(item);
                String json = JSON.toJSONString(itemDoc);
                bulkRequest.add(new IndexRequest("item").id(itemDoc.getId().toString()).source(json, XContentType.JSON));
            }

<think>我们正在处理一个Java类型转换异常:`java.lang.ClassCastException:java.util.LinkedHashMapcannotbecasttocom.yitao.core.entity.pojo.PProductAttr`根据引用资料,问题通常发生在从Redis或其他远程调用中获取数据时,原本期望的对象被反序列化为`LinkedHashMap`,而不是我们期望的特定类。这是由于序列化/反序列化过程中类型信息丢失导致的。解决方案汇总:1.使用ObjectMapper进行类型转换(如引用[3]和[4]所示)2.使用JSON工具类进行转换(如引用[4])3.确保序列化/反序列化时使用正确的类型信息具体步骤:方案一:使用ObjectMapper(推荐)假设我们从某个地方(如Redis)获取了一个对象,这个对象实际上是一个`LinkedHashMap`,但我们期望它是`PProductAttr`的列表或单个对象。如果获取到的是单个对象(即一个`LinkedHashMap`,代表一个`PProductAttr`):```javaObjectobject=redisTemplate.opsForValue().get("key");//这里返回的是LinkedHashMapObjectMappermapper=newObjectMapper();PProductAttrproductAttr=mapper.convertValue(object,PProductAttr.class);```如果获取到的是一个对象列表(即一个`List<LinkedHashMap>`,但我们需要`List<PProductAttr>`):```javaObjectobject=redisTemplate.opsForValue().get("key");//返回的是List<LinkedHashMap>//首先将它转换为ListList<LinkedHashMap>list=(List<LinkedHashMap>)object;//然后使用ObjectMapper转换ObjectMappermapper=newObjectMapper();List<PProductAttr>productAttrs=newArrayList<>();for(LinkedHashMapmap:list){productAttrs.add(mapper.convertValue(map,PProductAttr.class));}```或者像引用[3]那样使用`TypeReference`:```javaList<LinkedHashMap>list=(List<LinkedHashMap>)object;ObjectMappermapper=newObjectMapper();List<PProductAttr>productAttrs=mapper.convertValue(list,newTypeReference<List<PProductAttr>>(){});```方案二:使用JSON工具(如FastJSON或Jackson)引用[4]提供了使用FastJSON的示例:```java//假设object是从Redis取出的单个对象(LinkedHashMap)StringjsonString=JSON.toJSONString(object);//使用FastJSON将对象转为JSON字符串PProductAttrproductAttr=JSONObject.parseObject(jsonString,PProductAttr.class);//然后再转成目标对象```如果是一个列表:```javaStringjsonString=JSON.toJSONString(object);//object是List<LinkedHashMap>List<PProductAttr>productAttrs=JSONObject.parseArray(jsonString,PProductAttr.class);```注意:这些方法都需要确保`PProductAttr`类有无参构造函数,并且字段能够匹配(名称和类型)。另外,从引用[2]中我们了解到,在远程调用(如OpenFeign)中,由于底层序列化的原因,可能会自动使用`LinkedHashMap`。因此,在使用Feign客户端时,确保返回类型是具体的类而不是`Map`或`Object`。如果调用方得到的是`LinkedHashMap`,同样可以用上述方法转换。其他建议:1.检查Redis的序列化配置:确保RedisTemplate的序列化器配置正确,使用Jackson2JsonRedisSerializer等可以保留类型信息的序列化器。例如,在SpringDataRedis中配置:```java@BeanpublicRedisTemplate<String,Object>redisTemplate(RedisConnectionFactoryfactory){RedisTemplate<String,Object>template=newRedisTemplate<>();template.setConnectionFactory(factory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值Jackson2JsonRedisSerializer<Object>serializer=newJackson2JsonRedisSerializer<>(Object.class);ObjectMapperobjectMapper=newObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);serializer.setObjectMapper(objectMapper);template.setValueSerializer(serializer);//设置key的序列化方式template.setKeySerializer(newStringRedisSerializer());returntemplate;}```这样配置后,从Redis读取的数据如果是对象,则会被正确反序列化为原来的类型,避免出现`LinkedHashMap`。2.如果你是在从Redis中读取数据时出现此问题,检查存储数据时是否使用了正确的序列化方式。总结:根据具体情况,我们可以采用手动转换(使用ObjectMapper或JSON工具)或配置正确的序列化器来解决。相关问题:1.如何配置SpringDataRedis以避免类型转换异常?2.Feign客户端调用中如何处理类型转换异常?3.使用ObjectMapper进行类型转换时需要注意什么?</think> ### 解决 `java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to PProductAttr` 这个异常通常发生在反序列化过程中,当JSON数据被自动解析为`LinkedHashMap`而非目标类时。以下是完整解决方案: #### 🎯 核心解决方案(4种实现方式) 1. **`ObjectMapper` 显式转换(推荐)** ```java // 从Redis/Feign获取的原始数据 Object rawData = redisTemplate.opsForValue().get("key"); ObjectMapper mapper = new ObjectMapper(); // 单个对象转换 PProductAttr productAttr = mapper.convertValue(rawData, PProductAttr.class); // 集合转换 List<PProductAttr> productList = mapper.convertValue(rawData, new TypeReference<List<PProductAttr>>(){}); ``` *需要确保目标类有无参构造器* 2. **JSON库直接转换(FastJSON/Jackson)** ```java // FastJSON 实现 String jsonStr = JSON.toJSONString(rawData); PProductAttr productAttr = JSON.parseObject(jsonStr, PProductAttr.class); // Jackson 实现 PProductAttr productAttr = new ObjectMapper() .readValue(rawData.toString(), PProductAttr.class); ``` 3. **类型安全反序列化(Spring Boot)** 在RedisTemplate配置中启用类型提示: ```java @Bean public RedisTemplate<String, PProductAttr> redisTemplate() { RedisTemplate<String, PProductAttr> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory()); Jackson2JsonRedisSerializer<PProductAttr> serializer = new Jackson2JsonRedisSerializer<>(PProductAttr.class); template.setDefaultSerializer(serializer); return template; } ``` 4. **避免无类型泛型声明(重要!)** ```diff // 错误写法 ❌ - List list = redisTemplate.opsForValue().get("key"); // 正确写法 ✅ + List<PProductAttr> list = redisTemplate.opsForValue().get("key"); ``` #### ⚠️ 根本原因 1. **序列化机制问题** 当使用默认的JDK序列化或未配置类型信息时,Spring Data Redis/Feign会将JSON解析为`LinkedHashMap`而非具体类型[^1][^2] 2. **类型擦除** Java泛型在运行时被擦除,容器类对象(如`List<Object>`)会丢失元素类型信息 3. **数据源差异** 远程调用(如Feign)与本地方法返回的数据结构不一致[^2] #### 🔧 预防措施 1. **强制类型声明** ```java // 方法返回值明确定义 public PProductAttr getProductAttr(String id) { ... } // 避免使用无类型Map // public Map<String, Object> getProductData() { ... } ``` 2. **配置全局序列化(application.yml)** ```yaml spring: redis: valueSerializer: jackson jackson: default-typing: enable ``` 3. **DTO类规范** ```java // 必须包含无参构造器 + getter/setter public class PProductAttr { private String attrName; private Integer attrType; public PProductAttr() {} // 关键! } ``` > **验证方法**:在调试器中检查数据源类型,如果是`LinkedHashMap`而非目标类,则必须使用显式转换。 相关问题: 1. 如何配置Spring Data Redis避免类型转换异常? 2. FastJSON和Jackson在类型转换中有哪些区别? 3. 泛型擦除如何影响Java的反序列化过程? 4. 为什么Feign远程调用会返回LinkedHashMap? [^1]: Spring Data Redis类型处理机制 [^2]: Feign客户端反序列化原理 [^3]: ObjectMapper类型转换规范 [^4]: JSON库的类型安全实践
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值