Fastjson与Gson序列化反序列化变量名规范问题

一、大家先看个例子:

以上代码的setter/getter是使用Intellij IDEA自动生成的,仔细观察以上代码,你会发现以下规律:

  • 基本类型自动生成的getter和setter方法,名称都是isXXX()和setXXX()形式的。
  • 包装类型自动生成的getter和setter方法,名称都是getXXX()和setXXX()形式的。

我们可以发现,虽然Bean1和Bean2中的成员变量的名称不同,一个是success,另外一个是isSuccess,但是他们自动生成的getter和setter方法名称都是isSuccess和setSuccess。

为什么会这样呢?
Java Bean中关于setter/getter的规范
关于Java Bean中的getter/setter方法的定义其实是有明确的规定的,根据JavaBeans(TM) Specificationttps://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/)规定,
如果是普通的参数propertyName,要以以下方式定义其setter/getter:

  • public \<PropertyType> get\<PropertyName>();
  • public void set\<PropertyName>(\<PropertyType> a);

 但是,布尔类型的变量propertyName则是单独定义的:

  • public boolean is\<PropertyName>();
  • public void set\<PropertyName>(boolean m);


通过对照这份JavaBeans规范,我们发现,在Bean1中,变量名为isSuccess,如果严格按照规范定义的话,他的getter方法应该叫isIsSuccess。但是很多IDE都会默认生成为isSuccess。
那这样做会带来什么问题呢。
在一般情况下,其实是没有影响的。但是有一种特殊情况就会有问题,那就是发生序列化的时候。

序列化带来的影响


关于序列化和反序列化请参考Java对象的序列化与反序列化(https://www.hollischuang.com/archives/1150)。
我们这里拿比较常用的JSON序列化来举例,看看看常用的fastJson和Gson之间有何区别:

以上代码的Bean1中,只有一个成员变量即isSuccess,四个方法,分别是IDE帮我们自动生成的isSuccess和setSuccess,
另外一个是增加的一个符合getter命名规范的方法,最后一个增加的一个布符合getter命名规范的方法。

以上代码输出结果:

在fastjson的结果中,原来类中的isSuccess字段被序列化成success,并且其中还包含hello值。而Gson中只有isSuccess字段。

我们可以得出结论:

  • fastjson在把对象序列化成json字符串的时候,是通过反射遍历出该类中的所有getter方法**,得到getHello和isSuccess,然后根据JavaBeans规则,他会认为这是两个属性hello和success的值。直接序列化成json:{"hello":"hello","success":true}
  • 但是Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json:{“isSuccess”:true}

可以看到,由于不同的序列化工具,在进行序列化的时候使用到的策略是不一样的,所以,对于同一个类的同一个对象的序列化结果可能是不同的。
结论只知道了,但是我更感兴趣的是他们是如何处理的呢?分析源码后可知:

下图是fsonjson的处理流程图:

fastjson通过getter获取名字的方法:
 

Gson的处理流程图

Gson通过属性获取名字的方法

看到这里大家是不是豁然开朗了,也印证了上面提到的结论;

 接下来,那么如果对于同一个对象,我使用fastjson进行序列化,再使用Gson反序列化会发生什么?

这和我们预期的结果完全相反,原因是因为JSON框架通过扫描所有的getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,把Bean3对象序列化城字符串后内容为{"success":true}。
根据{"success":true}这个json串,Gson框架在通过解析后,通过反射寻找Bean3类中的success属性,但是Bean3类中只有isSuccess属性,所以,最终反序列化后的Bean类的对象中,isSuccess则会使用默认值false。
但是,一旦以上代码发生在生产环境,这绝对是一个致命的问题。

Gson的反序列化处理流程图:

 

总结:


如果我们用的是阿里的fastjson序列化工具那么我们就要按照阿里的手册来
在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规定:

 

但是看过fastjson源码之后之后你会发现,

原因在于fastjson源码是这样处理的,如下图:

上面举例都是不规范的只是为了说明存在的问题,

但是在平时开发过程中定义POJO变量时要符合JavaBeans的规范。这样无论永哪一种序列化框架,执行结果都一样。就从源头避免了这个问题。

 

 

学习链接:

https://maimai.cn/article/detail?fid=987324269&efid=TFCN35SpHSKgL7zwmyVneg

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值