JavaBean定义
无规矩不成方圆,Java IDE在代码检查或者自动生成时都要遵循一定的Java规范(并非100%,但就是因为不是100%按规范才容易出问题),先来看一下Java规范对于javabean时如何定义的。
据JavaBeans™ Specification规定,如果是普通的参数propertyName,要以以下方式定义其setter/getter:
public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> a);
但是,布尔类型的变量则是单独定义的:
public boolean is<PropertyName>();
public void set<PropertyName>(boolean m);
如果严格按照规范定义的话,他的getter方法应该叫isIsSuccess。但是很多IDE都会默认生成为isSuccess,看一下在Linux系统下eclipse2020版生成的代码:
public class Demo {
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
Boolean success;
}
class Demo1 {
public Boolean getIsSuccess() {
return isSuccess;
}
public void setIsSuccess(Boolean isSuccess) {
this.isSuccess = isSuccess;
}
Boolean isSuccess;
}
class Demo2 {
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
boolean success;
}
class Demo3 {
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
boolean isSuccess;
}
可以看到Demo3的get方法并非严格按照规范命名,如果严格按照命名规则则应该是isIsSuccess();有的编译器也会把Demo1的Boolean getIsSuccess() 命名为getSuccess();正是由于每个IDE不是严格按照规范,在一般情况下是没有影响的,但是有一种特殊情况就会有问题,那就是发生序列化的时候。
序列化时会产生什么问题?
以Demo3为列,在类中增加了一个get方法,看不同的框架序列化会产生什么问题?
class Demo3 implements Serializable{
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
boolean isSuccess;
public String getTest(){
return "test";
}
}
public static void main(String[] args) {
//定一个Model3类型
Demo3 demo3 = new Demo3();
demo3.setSuccess(true);
//使用fastjson(1.2.16)序列化成字符串并输出
System.out.println(JSON.toJSONString(demo3));
//使用Gson(2.8.5)序列化成字符串并输出
Gson gson =new Gson();
System.out.println(gson.toJson(demo3));
}
通过运行,可以看到如下结果:
{"success":true,"test":"test"}
{"isSuccess":true}
在fastjson的结果中,原来类中的isSuccess字段被序列化成success,并且其中还包含test值。而Gson中只有isSuccess字段。
我们可以得出结论:fastjson在把对象序列化成json字符串的时候,是通过反射遍历出该类中的所有getter方法,得到getTest和isSuccess,然后根据JavaBeans规则,他会认为这是两个属性test和success的值。直接序列化成json:{“test”:”test”,”success”:true}
但是Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json:{“isSuccess”:true}
可以看到,由于不同的序列化工具,在进行序列化的时候使用到的策略是不一样的,所以,对于同一个类的同一个对象的序列化结果可能是不同的。
通过一个框架序列化另一个框架反序列化
修改下Demo3的源码:
class Demo3 implements Serializable{
@Override
public String toString() {
return "Demo3 [isSuccess=" + isSuccess + "]";
}
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
boolean isSuccess;
}
使用fastjson序列化,Gson反序列化
public static void main(String[] args) {
//定一个Model3类型
Demo3 demo3 = new Demo3();
demo3.setSuccess(true);
Gson gson =new Gson();
System.out.println(gson.fromJson(JSON.toJSONString(demo3),Demo3.class));
}
看结果:
Demo3 [isSuccess=false]
这和我们预期的结果完全相反,原因是因为JSON框架通过扫描所有的getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,把model对象序列化城字符串后内容为{“success”:true}。
根据{“success”:true}这个json串,Gson框架在通过解析后,通过反射寻找Model类中的success属性,但是Model类中只有isSuccess属性,所以,最终反序列化后的Model类的对象中,isSuccess则会使用默认值false。