POJO類中布爾類型為啥不讓用isXxx命名


源碼面前,了無秘密

《阿里開發規范泰山版》(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)

歡迎掃碼關注我的個人公眾號,獲取最新文章↓


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM