背景

前几周在做项目fetch切换,即将HttpUtils调用改成使用Feign调用。大概代码如下:

// 原代码
String resultJson = HttpUtil.get(url + "/fin/test?code=" + code, null);
RespDTO<Result> respDTO = JSON.parseObject(resultJson, new TypeReference<RespDTO<Result>>() {}); // 现代码如下
RespDTO<Result> respDTO = urlClient.getTest(code);

代码上线后,出现了异常。表现为:respDTO的某个字段为null,但是第三方是有传过来这个值的。

问题复现

public static void main(String[] args) throws JsonProcessingException, IntrospectionException {
String data = "{\"aFiled\":10,\"normalFiled\":20}"; // 原方式
Domain domain = JSON.parseObject(data, Domain.class);
System.out.println("domain = " + domain.getAFiled()); // feign方式
ObjectMapper mapper = new ObjectMapper();
Domain domain1 = mapper.readValue(data, Domain.class);
System.out.println("domain1 = " + domain1.getAFiled());
}

https://github.com/wangjie-fourth/jackson01

问题分析

既然请求返回数据,但接收对象没有对应的值,那就说明字符串没有反序列化到指定的变量名上。改之前是使用FastJson反序列化数据,改之后的Feign默认是采用Jackson反序列化数据。那么为什么FastJson可以反序列化aFiledJackson不可以呢?

FastJson是根据变量名称来反序列化的,也就是说它接收到aFiled数据,就会到对象找aFiled变量名,然后附上值;而Jackson默认是根据JavaBean规范找到对应属性后再赋值,也就是说Jackson并没有在这个对象找到aFiled属性。

JavaBean属性名称跟变量名称是不一定相同的。JavaBean是通过对象的getset方法来确定对象属性,其属性名称是由其对象变量来决定的,通常的逻辑是:将属性首字母转成大写。但也有例外就是,前俩个字母都是大写的情况:

8.8 Capitalization of inferred names.

When we use design patterns to infer a property or event name, we need to decide what rulesto follow for capitalizing the inferred name. If we extract the name from the middle of a normalmixedCase style Java name then the name will, by default, begin with a capital letter.

Java programmers are accustomed to having normal identifiers start with lower case letters.Vigorous reviewer input has convinced us that we should follow this same conventional rulefor property and event names.

Thus when we extract a property or event name from the middle of an existing Java name, wenormally convert the first character to lower case. However to support the occasional use of allupper-case names, we check if the first two characters of the name are both upper case and ifso leave it alone. So for example,

“FooBah” becomes “fooBah”

“Z” becomes “z”

“URL” becomes “URL”

We provide a method Introspector.decapitalize which implements this conversion rule.

Jackson根据getset方法来确定属性的名称。而变量前俩个字母含有一个大写字母对应的属性名称会很怪。如下:



我们项目上使用的是lombok,其生成的getset方法是不遵循JavaBean规范的,只是将变量名的首字母大写而已,所以它生成aFiled的方法是getAFiled

所以,Jackson在接收到aFiled属性值,它会到对象找setaFiled方法,自然这个对象是没有这个方法的,所以就没映射到aFiled字段上。

解决办法

jackson可以使用@JsonProperty注解来指定属性名称。

总结

出现这个就是因为JavaBean规范对前俩个字母含有大写字母的变量名做了特殊处理。 Jackson遵循JavaBean规范来反序列化,而项目使用的Lombok插件是不遵循JavaBean规范。

扩展

JavaBean规范对前俩个字母含有大写字母的处理不全

针对变量名前俩个字母做个穷举,就是如下对象:

public class Domain {
private Integer aFiled;
private Integer afiled;
private Integer AFiled;
private Integer Afiled; public Integer getaFiled() {
return aFiled;
} public void setaFiled(Integer aFiled) {
this.aFiled = aFiled;
} public Integer getAfiled() {
return afiled;
} public void setAfiled(Integer afiled) {
this.afiled = afiled;
} public Integer getAFiled() {
return AFiled;
} public void setAFiled(Integer AFiled) {
this.AFiled = AFiled;
}
}

你会发现afiledAfiled生成的属性是一致的!不过好在项目中没有人只将首字母大写这种命名风格。

谨慎用Lombok替换旧项目的getset方法

旧项目一般都是用Idea来生成getset方法,而Idea是遵循JavaBean规范来生成属性的。所以,旧项目如果含有前俩个仅含有一个大写字母时,尽量不用药lombok去替换。

参考链接

java bean规范文档

jackson 序列化问题

最新文章

  1. Linux驱动开发——pr_fmt的用法
  2. Mysql 中的事件//定时任务
  3. grep 使用或条件 ( grep -e )
  4. python 获取一个列表有多少连续列表
  5. 安装android
  6. 【转】ssh登录慢,等待输入密码时间长的解决办法
  7. mybatis中的mapxml的语法
  8. Visual Studio Enterprise 2015下载 Update3
  9. Oracle 10g -- 修改DB的编码
  10. Python参数组合
  11. smarty 操作符号,大于、小于。。。
  12. 无DLL线程注入
  13. 武汉科技大学ACM :1005: C语言程序设计教程(第三版)课后习题6.6
  14. python成长之路9——socket和socketserver
  15. BZOJ2733 永无乡【splay启发式合并】
  16. 自动化运维工具——puppet详解(二)
  17. DBC文件小结
  18. centos 7中监控mysql 数据库脚本(监控端口)
  19. 手动建立mapping以及增加属性
  20. oracle中sequence(自增序号)的用法

热门文章

  1. 在Mac上打开多个Unity实例
  2. JetBrain破解
  3. Dungeon Master(三维bfs)
  4. ASP调用WEBSERVICE并对返回结果进行解析时遇到的问题
  5. taro-script 0.4 发布,基于Taro v3的js解释器组件
  6. linux下设置账户锁定阈值:登录失败n次,多长时间后解锁重新登录
  7. Linux实战(11):Centos安装Jenkins
  8. Prometheus之Exporter开发
  9. 5.Strom-事务型拓扑
  10. Qt 展示pdf内容(新窗口或嵌入,pdfjs,linux)