美文网首页
fastjson转换json时,碰到的那些首字母大小写转换的坑!

fastjson转换json时,碰到的那些首字母大小写转换的坑!

作者: King斌 | 来源:发表于2022-10-12 13:40 被阅读0次

    坑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;
    }
    

    也就是说,连续大写开头的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对应的注解,这个注解也是无效的。

    解决

    1. 碰到这种propertyName,就不要用lombok生成的getter/setter了,自己写,保持首字符小写,如:getiPhone/setiPhone,只要在代码里面有这两个方法,lombok就不会自动生成,lombok是按忽略大小写后的propertyName判断的。
    2. 把propertyName第二个字符改成小写,或者重新取个名字,并用@JSONField注明正确的名称,如:
     @Getter
     @ JSONField(name = "iPhone")
     private String iphone = "1";
    

    相关文章

      网友评论

          本文标题:fastjson转换json时,碰到的那些首字母大小写转换的坑!

          本文链接:https://www.haomeiwen.com/subject/uxbtzrtx.html