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

一、大家先看个例子:

Fastjson与Gson序列化反序列化变量名规范问题_第1张图片

以上代码的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 \ get\();
  • public void set\(\ a);

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

  • public boolean is\();
  • public void set\(boolean m);

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

序列化带来的影响


关于序列化和反序列化请参考Java对象的序列化与反序列化(https://www.hollischuang.com/archives/1150)。
我们这里拿比较常用的JSON序列化来举例,看看看常用的fastJson和Gson之间有何区别:
Fastjson与Gson序列化反序列化变量名规范问题_第3张图片
以上代码的Bean1中,只有一个成员变量即isSuccess,四个方法,分别是IDE帮我们自动生成的isSuccess和setSuccess,
另外一个是增加的一个符合getter命名规范的方法,最后一个增加的一个布符合getter命名规范的方法。

以上代码输出结果:

Fastjson与Gson序列化反序列化变量名规范问题_第4张图片

在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与Gson序列化反序列化变量名规范问题_第5张图片

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

Fastjson与Gson序列化反序列化变量名规范问题_第6张图片Fastjson与Gson序列化反序列化变量名规范问题_第7张图片

Gson的处理流程图

Fastjson与Gson序列化反序列化变量名规范问题_第8张图片

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

Fastjson与Gson序列化反序列化变量名规范问题_第9张图片

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

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

Fastjson与Gson序列化反序列化变量名规范问题_第10张图片

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

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

Fastjson与Gson序列化反序列化变量名规范问题_第11张图片

 

总结:


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

 

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

Fastjson与Gson序列化反序列化变量名规范问题_第12张图片

Fastjson与Gson序列化反序列化变量名规范问题_第13张图片

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

Fastjson与Gson序列化反序列化变量名规范问题_第14张图片

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

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

 

 

学习链接:

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

你可能感兴趣的:(java,fastjson,Gson,序列化与反序列化)