java model 序列化_Java序列化对字段名的影响

前段时间遇到一个问题,序列化之后原本类中的属性名发生了变化,原本isDel序列化之后得到的是del,为此查了一下相关资料,发现和序列化机制有关

在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规定:

337de42510b1fc580d1a04319624fc6d.png

为此我们要看一下POJO中布尔类型变量不同的命名

classModel1 {privateBoolean isSuccess;public voidsetSuccess(Boolean success) {

isSuccess=success;

}publicBoolean getSuccess() {returnisSuccess;

}

}classModel2 {privateBoolean success;publicBoolean getSuccess() {returnsuccess;

}public voidsetSuccess(Boolean success) {this.success =success;

}

}classModel3 {private booleanisSuccess;public booleanisSuccess() {returnisSuccess;

}public void setSuccess(booleansuccess) {

isSuccess=success;

}

}classModel4 {private booleansuccess;public booleanisSuccess() {returnsuccess;

}public void setSuccess(booleansuccess) {this.success =success;

}

}

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

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

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

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

关于Java Bean中的getter/setter方法的定义其实是有明确的规定的,根据JavaBeans(TM) Specification规定,如果是普通的参数propertyName,要以以下方式定义其setter/getter:

https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/

public get();public void set(a);public boolean is();public void set(boolean m);

可以看boolean类型的变量方法是单独定义的,使用is方式

通过对照这份JavaBeans规范,我们发现,在Model4中,变量名为isSuccess,如果严格按照规范定义的话,他的getter方法应该叫isIsSuccess。但是很多IDE都会默认生成为isSuccess。

在序列化中,这样就会受到影响

@Dataclass Model3 implementsSerializable {private static final long serialVersionUID = 1836697963736227954L;privateInteger age;privateString name;private booleanisSuccess;private booleanisDel;publicString getUser(){return "Hello JWZ";

}

}

我们定义一个类,使用lombok,然后看序列化进行测试

//定一个Model3类型

Model3 model3 = newModel3();

model3.setSuccess(true);//使用fastjson(1.2.46)序列化model3成字符串并输出

System.out.println("Serializable Result With fastjson :" +JSON.toJSONString(model3));//使用Gson(2.8.5)序列化model3成字符串并输出

Gson gson =newGson();

System.out.println("Serializable Result With Gson :" +gson.toJson(model3));//使用jackson(2.9.6)序列化model3成字符串并输出

ObjectMapper om = newObjectMapper();

System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model3));

得到如下结果:

3c1373a704c3f24c277ec18c277f7b66.png

可以看到三种序列化的方式,

fastjson输出有值的数据,包含user,带is的字段被序列化不带is

Gson输出有值的数据,不包含user,带is的字段被序列化正常

Jackson输出所有有值和null的数据,包含user,带is的字段被序列化不带is

由此可以得出结论:

fastjson和Jackson是通过反射遍历getter方法,然后根据JavaBeans规则他会去掉is来获取属性值。

Gson是通过直接反射遍历类中所有属性。

现在我们试一下,对于同一个对象,如果用fastjson序列化,然后在使用Gson反序列化:

public static voidmain(String[] args) {

Model3 model3= newModel3();

model3.setSuccess(true);

String fastJSONString=JSON.toJSONString(model3);

System.out.println(fastJSONString);

Gson gson=newGson();

System.out.println(gson.fromJson(fastJSONString,Model3.class));

}

5e9f38d969b726410256788847d10e7b.png

isSuccess竟然变为false

因为JSON框架通过扫描所有的getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,把model对象序列化城字符串后内容为{"success":true}。

根据{"success":true}这个json串,Gson框架在通过解析后,通过反射寻找Model类中的success属性,但是Model类中只有isSuccess属性,所以,最终反序列化后的Model类的对象中,isSuccess则会使用默认值false。

因此,应尽量使用success式的命名来从源头避免这个问题。

延伸,布尔类型定义应使用Boolean还是boolean

布尔类型应该使用包装类型还是基本数据类型呢?

ef5e9e0d8d6503a5591c37102d758f79.png

public classTest {public static voidmain(String[] args) {

Model3 model3= newModel3();

System.out.println("model3 : " +model3);

}

}

@Dataclass Model3 implementsSerializable {booleansuccess;

Boolean del;

}

6d26460c7061b22561e07ce402a0491c.png

包装类型的默认值是null,基本类型的默认值输出了false,这在某些情况就会造成问题,建议在POJO和RPC的返回值中使用包装类型

所以在定义布尔类型变量时,应使用:

Boolean success;

参考:

《Java工程师成神之路》

《阿里巴巴Java开发手册》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值