关于Feign调用会将对象嵌套的Map转为LinkedHashMap的问题

又踩到Feign坑了←_←(冷笑话)

问题复现

方法提供者,返回一个Result对象,并将一个MemberVo对象封装到了Result对象中的一个哈希表中:

@ApiOperation(value = "根据用户id获取信息")
@GetMapping("/member/{id}")
public Result getUserInfo(@PathVariable String id){
    MemberVo loginInfoVo = memberService.getLoginInfo(id);
    return Result.ok().data("item", loginInfoVo);
}

Result的结构:

public class Result {
    private boolean flag;//是否成功
    private Integer code;//返回码
    private String message;//返回消息
    private Map<String,Object> data = new HashMap<>();//返回数据
    //...
}

Feign客户端:

@Component
@FeignClient(value = "service-ucenter",fallback = MemberFallback.class)
public interface MemberFeign {

    @GetMapping("/ucenter/member/{id}")
    public Result getUserInfo(@PathVariable String id);
}

Feign调用该方法,想从Result对象的哈希表中取出MemberVo对象:

Result userInfo = memberFeign.getUserInfo(memberId);
MemberVo memberVo = (MemberVo) userInfo.getData().get("item");

就这两句话,看起来合情合理,我一开始也觉得应该没问题,结果报错:

java.util.LinkedHashMap cannot be cast to com.guli.ucenter.entity.vo.MemberVo

问题分析

关于Feign调用会将对象嵌套的Map转为LinkedHashMap的问题

调试发现,Feign调用后取到的Result对象的data已经不是一个HashMap了,而是一个LinkedHashMap,里面存放的item对应的value,也变成了一个LinkedHashMap,保留了原来MemberVo对象的属性,但并不是一个MemberVo对象。

原因其实不难想到,毕竟Feign调用的实质还是HTTP请求,中间还是经过了Json与对象的互转,转换过程中要进行对象关系映射,只能根据给它的类获取结构,而Result中data声明为一个Map接口,转换为LinkedHashMap也说得通,至于原来哈希表中的对象,根据Result类结构完全无法获知里面的哈希表中的数据到底是什么类型,当然也无法将它转换回原来的类对象。

可以猜测Feign会将Map接口(体现为json的object)和map中的对象(也体现为json中的object)都会转换为LinkedHashMap实例,至于为什么是LinkedHashMap而不是HashMap可能是为了维持键值对之间的顺序。

解决方案

关于解决方案,我想到的是,要么把LinkedHashMap当原来的类对象使用,毕竟也可以获取所有的属性和值;要么就专门为Feign调用设计一个方法,不要返回嵌套Map的Result对象;要么就将LinkedHashMap转为原来的类对象。

最后我选择了专门为Feign调用设计一个方法?

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e5%85%b3%e4%ba%8efeign%e8%b0%83%e7%94%a8%e4%bc%9a%e5%b0%86%e5%af%b9%e8%b1%a1%e5%b5%8c%e5%a5%97%e7%9a%84map%e8%bd%ac%e4%b8%balinkedhashmap%e7%9a%84%e9%97%ae%e9%a2%98/