共计 2332 个字符,预计需要花费 6 分钟才能阅读完成。
源码背后,了无机密。
大家好,我是 Java 课代表。想要理解更多 Java 信息,请关注公众号:Java 课代表。
《阿里开发标准泰山版》(2020.04.22)–> 编程规约 –>(一) 命名格调 –> 第 8 条规定:
【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则局部框架解析会引起序列化谬误。
对于这样一条【强制】级别的规定,尽管标准中做了简略的阐明,但仍然显得很不起眼,以至于我尽管标准背的很熟,仍然踩到了这个坑。
0 起因
最近写了一个钉钉告警工具类,对于这种需要明确,开发文档清晰的工作,写代码信手拈来,很快就写完了。
然而自测的时候却发现 @所有人这个接口始终过不了单元测试,通过一番追踪,终于找到起因,于是有了本文。
1 问题重现
自身发钉钉音讯就是一个 post 申请的事,而且钉钉有阿里背书,调用不通那天然是我这个开发者的问题喽。
上面是钉钉的接口阐明,参数 isAtAll
示意是否 @所有人
{
"msgtype": "text",
"text": {"content": "我就是我, 是不一样的烟火 @156xxxx8827"},
"at": {
"atMobiles": [
"156xxxx8827",
"189xxxx8325"
],
"isAtAll": false
}
}
依据这个 json 串,我编写了如下的 POJO 类与之对应,并应用 fastjson 进行 json 序列化
public class Message {
/**
* 音讯类型
**/
private String msgtype = "text";
/**
* 音讯内容对象
**/
private Text text;
/**
* 被 @对象
**/
private At at;
public static class At{
/**
* 被 @人电话
**/
private List<String> atMobiles;
/**
* 是否 @所有人
**/
private boolean isAtAll;
// 省略 getter、setter
}
// 省略无关代码...
}
问题就出在 private boolean isAtAll;
这个字段上,有没有发现阿里的这个参数违反了开篇提到的开发标准?应用 fastjson 序列化之后,该属性理论转化为了:
"atAll": true
这个坑爹货,把后面的 is 给吃了!导致无奈 @所有人
2 追根溯源
为什么序列化之后把 is 吃了呢?带着这个问题我追踪了一下 fastjson 的源码,发现在序列化的时候,其应用的是属性的 getter 办法名,而 isAtAll
字段主动生成的 getter、setter 为:
public boolean isAtAll() {return isAtAll;}
public void setAtAll(boolean atAll) {isAtAll = atAll;}
对应的 fastjson 中对办法名的解决在 com.alibaba.fastjson.util.TypeUtils.computeGetters
中, 源码摘录如下:
if(methodName.startsWith("is")){if(methodName.length() < 3){continue;}
if(method.getReturnType() != Boolean.TYPE
&& method.getReturnType() != Boolean.class){continue;}
String propertyName;
Field field = null;
if(Character.isUpperCase(c2)){if(compatibleWithJavaBean){propertyName = decapitalize(methodName.substring(2));
} else{propertyName = Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3);
}
propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 2);
}
也就是说,对于 is 结尾的办法,fastjson 先把第 3 个字符截取进去,如果该字符是大写,就转换为小写,并且拼装残余的办法名组成属性名。
例如:isAtAll
办法拼装进去的属性名就是 atAll
,最终后果就是把咱们的is
给吃了!
3 解决办法
既然问题本源曾经找到了,那咱们只须要隔靴搔痒就能够了,这里针对不同利用场景,课代表给大家总结三种解决办法:
- 对于有批改权限的代码,要严格遵守开发标准,POJO 类中的布尔类型属性不要用
is
结尾命名,如果有,改掉 - 对于第三方接口,参数里有相似
isXXX
这样的参数,能够在对应属性字段上应用 fastjson 的@JSONField(name = "anotherName")
来定制属性名 - 能够手动批改 getter 和 setter 办法名
4 引申
SpringBoot 集成了 jackson,默认应用 jackson 来进行 json 序列化,通过测试,jackson 也存在吃掉 is
的状况,原理与 fastjson 相似,就不做过多解释了,开发过程中恪守文中提及的解决办法即可
参考
- fastjson 源码
- 《阿里开发标准泰山版》(2020.04.22)
【举荐浏览】
RabbitMQ 教程
应用 Spring Validation 优雅地校验参数
Freemarker 教程(一)- 模板开发手册
Dubbo 异样解决源码探索及其最佳实际
下载的附件名总乱码?你该去读一下 RFC 文档了!
深入浅出 MySQL 优先队列(你肯定会踩到的 order by limit 问题)
码字不易,欢送点赞关注和分享。
搜寻:【Java 课代表】,关注公众号,每日一更,及时获取更多 Java 干货。