坑0x01 全大寫的鍵名
這種情況在api定義里面很常見,如下:
private String TEST = "1";
public String getTEST() {
return this.TEST
}
在fastjson轉換后歼疮,變成:json{ "tEST": "1"}
杂抽,與預期不符,首字母變成小寫了韩脏。
原因:
fastjson在將bean轉換為json時缩麸,先取出對應的methodName: getTEST,從methodName的第4個字符開始赡矢,取出propertyName:TEST杭朱,它默認認為這個propertyName的首字母是在定義getter的時候被寫成大寫的,現在要轉成小寫:
propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
結果吹散,正確的TEST就被轉成錯誤的tEST了弧械。
解決:
解決這個問題比較簡單,在轉換前空民,多加一行代碼:
TypeUtils.compatibleWithJavaBean =true;
此時刃唐,fastjson會先判斷propertyName長度大于1羞迷、且頭兩個字符都是大寫時,不做轉換:
if(name.length() > 1
&& Character.isUpperCase(name.charAt(1))
&& Character.isUpperCase(name.charAt(0))){
return name;
}
也就是說画饥,連續(xù)大寫開頭的propertyName衔瓮,在轉換時,會保持原樣抖甘。
坑0x02 第一個字符大寫热鞍,第二個字符不是大寫的鍵名
按坑0x01里面講的設置TypeUtils.compatibleWithJavaBean=true
后,如果有如下的鍵名衔彻,依然會出問題:
private String T_EST = "1";
private String Test = "2";
public String getT_EST() { return this.T_EST}
public String getTest() { return this.Test}
在fastjson轉換后薇宠,變成:{ "t_EST": "1", "test":"2"}
,又是一個坑艰额。
原因:
從坑0x01的最后一段代碼可以看出昼接,要想fastjson不改首字符,除了需要設置compatibleWithJavaBean
外悴晰,propertyName的第二個字符也必須是大寫慢睡。在坑0x02這里,兩個propertyName都無法通過判斷铡溪,首字母就要被轉換成小寫了漂辐。
解決
要解決這個問題,在轉換前棕硫,必須再加一行代碼:
TypeUtils.compatibleWithFieldName = true;
Fastjson里面對應的處理代碼如下:
if(compatibleWithFieldName){
if(!fieldCacheMap.containsKey(propertyName)){
String tempPropertyName = methodName.substring(fromIdx);
return fieldCacheMap.containsKey(tempPropertyName) ? tempPropertyName : propertyName;
}
}
fastjson在按坑0x01所述的過程處理完propertyName后髓涯,propertyName的首字符被轉換為小寫,然后會在bean的的field列表里面找一遍轉換后的名稱哈扮。如果找不到纬纪,就從methodName里面重新取get后面的字符串,然后再到field列表里面找一遍滑肉,如果找到包各,就用原propertyName,如果找不到就用首字符被轉換的名稱靶庙。
坑0x03 首字符小寫问畅,第二個字符大寫的鍵名
這個坑與lombok相關,嚴格來說六荒,應該是lombok挖的坑护姆。
如上所述,就算你按坑0x01掏击、0x02設置了卵皂,如果在工程里面用lombok時,有如下的鍵名定義砚亭,依然要被坑:
@Getter
private String iPhone = "1";
在fastjson轉換后灯变,變成:{ "IPhone": "1" }
豺旬,首字符變大寫了,WTF柒凉!
原因:
Lombok在自動生成getter的時候,會把propertyName的第一的字母改成大寫篓跛,等同如下代碼:
public String getIPhone(){return this.iPhone;}
問題就出在這個轉換上,get后面緊跟的字符變成大寫了。在eclipse吞彤、idea里面粤咪,如果自動生成代碼,get后的字符是小寫沐寺。
如前面坑0x01最后一段代碼林艘,fastjson在處理getter時,會判斷前兩個字符是不是大寫混坞,如果是的話狐援,就保持原樣,取到的propertyName就成了:IPhone究孕。但是在field列表里面啥酱,對應的propertyName是iPhone,就算開啟了compatibleWithFieldName
厨诸,fastjson用從getter中解析出來的IPhone镶殷,在field列表里面也找不到對應值,也只能保持IPhone這個名稱了微酬。
另外绘趋,就算在屬性前用了@JSONField(name = "iPhone")
注解,因為fastjson用從getter解析出來的propertyName找不到對應的field颗管,也無法讀出該field對應的注解陷遮,這個注解也是無效的。
解決
- 碰到這種propertyName垦江,就不要用lombok生成的getter/setter了拷呆,自己寫,保持首字符小寫疫粥,如:getiPhone/setiPhone茬斧,只要在代碼里面有這兩個方法,lombok就不會自動生成梗逮,lombok是按忽略大小寫后的propertyName判斷的项秉。
- 把propertyName第二個字符改成小寫,或者重新取個名字慷彤,并用@JSONField注明正確的名稱娄蔼,如:
@Getter
@ JSONField(name = "iPhone")
private String iphone = "1";