资讯专栏INFORMATION COLUMN

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

tyheist / 2845人阅读

摘要:某年某月的某一天,本汪在某个奇葩的公司,接手了某个奇葩的项目,遇到了一些奇葩的事情,就掉进关于做转换时,那些关于首字符大小写的坑。坑首字符小写,第二个字符大写的键名这个坑与相关,严格来说,应该是挖的坑。

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

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

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

坑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对应的注解,这个注解也是无效的。

解决

碰到这种propertyName,就不要用lombok生成的getter/setter了,自己写,保持首字符小写,如:getiPhone/setiPhone,只要在代码里面有这两个方法,lombok就不会自动生成,lombok是按忽略大小写后的propertyName判断的。

把propertyName第二个字符改成小写,或者重新取个名字,并用@JSONField注明正确的名称,如:

@Getter
@ JSONField(name = “iPhone”)
private String iphone = “1”;

关于lombok的这个坑,可以参考:http://xxxx.ooo/2017/using-lo...,lombok的作者也是死鸭子嘴硬,被提了n多的issue,就是不改。

以上,就是本汪在项目里面填坑的过程,不要问我为什么api里面的字段名称会定义成这副模样,本汪也不知道,汪!汪!!汪!!!

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71572.html

相关文章

  • CodeIgniter遇到

    摘要:文件夹中的文件首字母大写。因为在中我没有找到日期和字符串转换和格式化的灵活方法,所以在中处理格式化的问题。获取参数由于框架自身设计的问题,推荐尽量用方式请求后台服务,参数格式为格式。 1.controllers文件夹中的controller文件首字母大写。不大写也可以,但是环境兼容性不好,举个例子,我开发环境在mac电脑上,文件名首字母小写,服务可以正常访问;但是在阿里云服务器(deb...

    andot 评论0 收藏0
  • 流畅 Python - 3. 文本与字节

    摘要:不同编码器编码的相同的字符,最终的字节大小可能会不同。对于和,是由于对应编码不能处理字符串字节导致的。在另外两个规范化形式和的首字母缩略词中,字母表示兼容性。最后是双模,同一函数能接受字符串和字节进行操作。 对于字符串,我们接触得挺多的。而编码问题,也不时令人头疼的。 由于一开始接触的就是 Python3,所以一些在 Python2 上的编码上的坑我没遇到,甚至在 Python3 上都...

    e10101 评论0 收藏0
  • 高性能JSON框架之FastJson简单使用

    摘要:前言的介绍协议使用方便,越来越流行的处理器有很多这里我介绍一下是阿里的开源框架被不少企业使用是一个极其优秀的框架地址的特点数度快无论序列化和反序列化都是当之无愧的功能强大支持普通类包括任意或零依赖没有依赖其它任何类库的简单说明对于格式字符串 1.前言 1.1.FastJson的介绍: JSON协议使用方便,越来越流行,JSON的处理器有很多,这里我介绍一下FastJson,FastJs...

    Karrdy 评论0 收藏0
  • PHP中变量、注释、输出

    摘要:学习第一课变量注释输出上图是一段超级简单的输出的代码,是不是超级简单呢今天文章讲的就是这几行代码的知识。变量可以通过变量名访问。用来定义声明一个变量。有返回值,总是返回。输出格式化的字符串,有返回值,返回值是输出的字符串的长度。 来一波 Hello World,各位看官先感受下。PHP学习第一课:变量、注释、输出上图是一段超级简单的输出 Hello World 的代码,是不是超级简单呢...

    cgh1999520 评论0 收藏0
  • PHP常用函数之字符串处理

    摘要:为数组示例说明在中将字符串替换为即可。返回其中如果的数组值比的数组值长,将中多出来的数组元素在中匹配的字符串替换为空串,返回。 字符串大小写转换 strtoupper(string $str) //把字符串全部转换成大写字母 strtolower(string $str) //把字符串全部转换成小写字母 ucfirst(string $str) //把字符串的首字母转换成大写 ucw...

    SwordFly 评论0 收藏0

发表评论

0条评论

tyheist

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<