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

某年某月的某一天,本汪在某个奇葩的公司,接手了某个奇葩的项目,遇到了一些奇葩的事情,就掉进关于fastjson做bean to json转换时,那些关于首字符大小写的坑。

这个奇葩项目里面,api接口定义的是天马行空、云山雾绕,api里面的字段定义更是五花八门、千奇百怪,完全没有规则可言,都可以开个不符合规范的案例博物馆了。下面3个坑里面举的例子,那些奇葩的名称定义,都是在项目里面真实存在的,如有雷同,纯属不幸。

在api的处理过程里面,bean转换成json时,我们总是希望字段名是什么样的,转换成json就应该是什么样的,然而现实总是残酷的。

坑0x01 全大写的键名
这种情况在api定义里面很常见,如下:

1 private String TEST = “1”;
2 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、且头两个字符都是大写时,不做转换:

1 if(name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))){
2     return name;
3 }
也就是说,连续大写开头的propertyName,在转换时,会保持原样。

坑0x02 第一个字符大写,第二个字符不是大写的键名
按坑0x01里面讲的设置TypeUtils.compatibleWithJavaBean=true后,如果有如下的键名,依然会出问题:

1 private String T_EST = “1”;
2 private String Test = “2”;
3 public String getT_EST() { return this.T_EST}
4 public String getTest() { return this.Test}
在fastjson转换后,变成:{ “t_EST”: ”1”, “test”:”2”},又是一个坑。

原因:
从坑0x01的最后一段代码可以看出,要想fastjson不改首字符,除了需要设置compatibleWithJavaBean外,propertyName的第二个字符也必须是大写。在坑0x02这里,两个propertyName都无法通过判断,首字母就要被转换成小写了。

解决
要解决这个问题,在转换前,必须再加一行代码:
TypeUtils.compatibleWithFieldName = true;
Fastjson里面对应的处理代码如下:

1 if(compatibleWithFieldName){
2     if(!fieldCacheMap.containsKey(propertyName)){
3         String tempPropertyName = methodName.substring(fromIdx);
4         return fieldCacheMap.containsKey(tempPropertyName) ? tempPropertyName : propertyName;
5     }
6 }
fastjson在按坑0x01所述的过程处理完propertyName后,propertyName的首字符被转换为小写,然后会在bean的的field列表里面找一遍转换后的名称。如果找不到,就从methodName里面重新取get后面的字符串,然后再到field列表里面找一遍,如果找到,就用原propertyName,如果找不到就用首字符被转换的名称。

坑0x03 首字符小写,第二个字符大写的键名
这个坑与lombok相关,严格来说,应该是lombok挖的坑。
如上所述,就算你按坑0x01、0x02设置了,如果在工程里面用lombok时,有如下的键名定义,依然要被坑:

1 @Getter
2 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注明正确的名称,如:

1 @Getter
2 @ JSONField(name = “iPhone”)
3 private String iphone = “1”;
以上,就是本汪在项目里面填坑的过程,不要问我为什么api里面的字段名称会定义成这副模样,本汪也不知道,汪!汪!!汪!!!

关于fastjson的代码,都在TypeUtils.computeGetters里面。
@JSONField是个好东西,不嫌麻烦的话,就都加上吧。

文章转自:https://segmentfault.com/a/1190000015634321
--------------------- 
版权声明:本文为CSDN博主「weianlai」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weianlai/article/details/82328938

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值