fastjson生成Json时,首字母大写及日期类型问题

最近在将公司某个工具由C#翻译为Java,其中有Json文件的生成部分,为了与原程序生成交付物一致,所以属性名称开头也保持为大写。在最终生成json文件时,出现在大小写属性重复的问题。

参考文章:fastjson转换json时,碰到的那些首字母大小写转换的坑!
文章来源:segmentfault,作者:agamem。


前言

本文主要用于记录Json生成中属性首字母大小写转换问题,以及日期格式问题,给出两种解决方案。


一、全大写的键名

这种情况在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;
}

二、第一个字符大写,第二个字符不是大写的键名

设置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”},又是一个坑。

原因
要想fastjson不改首字符,除了需要设置compatibleWithJavaBean外,propertyName的第二个字符也必须是大写。在这里两个propertyName都无法通过判断,首字母就要被转换成小写了。

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

if(compatibleWithFieldName){
    if(!fieldCacheMap.containsKey(propertyName)){
        String tempPropertyName = methodName.substring(fromIdx);
        return fieldCacheMap.containsKey(tempPropertyName) ? tempPropertyName : propertyName;
    }
}

fastjson在按一所述的过程处理完propertyName后,propertyName的首字符被转换为小写,然后会在bean的的field列表里面找一遍转换后的名称。如果找不到,就从methodName里面重新取get后面的字符串,然后再到field列表里面找一遍,如果找到,就用原propertyName,如果找不到就用首字符被转换的名称。

三、首字符小写,第二个字符大写的键名

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

@Getter
private String iPhone =1;

在fastjson转换后,变成:{ “IPhone”: ”1” },首字符变大写了

原因

Lombok在自动生成getter的时候,会把propertyName的第一的字母改成大写,等同如下代码:

public String getIPhone(){return this.iPhone;}

问题就出在这个转换上,get后面紧跟的字符变成大写了。在eclipse、idea里面,如果自动生成代码,get后的字符是小写。

如前面一最后一段代码,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;
    

四、属性中Date被转换成long类型

可以使用JSONField标签

    /**
     * 更新时间,时间格式为标准时间戳格式,如2016-03-23 11:43:07
     */
    @JSONField(name="UpdateTime",format="yyyy-MM-dd HH:mm:ss")
    private String updateTime;

也可以使用toJSONStringWithDateFormat方法

转换时: JSON.toJSONStringWithDateFormat(object, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat);
ps: 此种无法对yyyy-MM-dd和包含时分秒的同时做处理.

总结

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值