源码背后,了无机密。
大家好,我是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 解决办法

既然问题本源曾经找到了,那咱们只须要隔靴搔痒就能够了,这里针对不同利用场景,课代表给大家总结三种解决办法:

  1. 对于有批改权限的代码,要严格遵守开发标准,POJO类中的布尔类型属性不要用is结尾命名,如果有,改掉
  2. 对于第三方接口,参数里有相似isXXX这样的参数,能够在对应属性字段上应用fastjson的@JSONField(name = "anotherName")来定制属性名
  3. 能够手动批改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干货。