背景
前几周在做项目fetch切换,即将HttpUtils调用改成使用Feign调用。大概代码如下:
// 原代码
String resultJson = HttpUtil.get(url + "/fin/test?code=" + code, null);
RespDTO respDTO = JSON.parseObject(resultJson, new TypeReference>() {});
// 现代码如下
RespDTO respDTO = urlClient.getTest(code);
代码上线后,出现了异常。表现为:respDTO的某个字段为null,但是第三方是有传过来这个值的。
问题复现
问题分析
既然请求返回数据,但接收对象没有对应的值,那就说明字符串没有反序列化到指定的变量名上。改之前是使用FastJson反序列化数据,改之后的Feign默认是采用Jackson反序列化数据。那么为什么FastJson可以反序列化aFiled而Jackson不可以呢?
FastJson是根据变量名称来反序列化的,也就是说它接收到aFiled数据,就会到对象找aFiled变量名,然后附上值;而Jackson默认是根据JavaBean规范找到对应属性后再赋值,也就是说Jackson并没有在这个对象找到aFiled属性。
JavaBean属性名称跟变量名称是不一定相同的。JavaBean是通过对象的get、set方法来确定对象属性,其属性名称是由其对象变量来决定的,通常的逻辑是:将属性首字母转成大写。但也有例外就是,前俩个字母都是大写的情况:
而Jackson根据get、set方法来确定属性的名称。而变量前俩个字母含有一个大写字母对应的属性名称会很怪。如下:
我们项目上使用的是lombok,其生成的get、set方法是不遵循JavaBean规范的,只是将变量名的首字母大写而已,所以它生成aFiled的方法是getAFiled。
所以,Jackson在接收到aFiled属性值,它会到对象找setaFiled方法,自然这个对象是没有这个方法的,所以就没映射到aFiled字段上。
解决办法
jackson可以使用@JsonProperty注解来指定属性名称。
总结
出现这个就是因为JavaBean规范对前俩个字母含有大写字母的变量名做了特殊处理。 Jackson遵循JavaBean规范来反序列化,而项目使用的Lombok插件是不遵循JavaBean规范。