Java序列化对字段名的影响

java 序列化 字段 序列 字段名


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

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

 

 

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

class Model1 {
private Boolean isSuccess;
public void setSuccess(Boolean success) {
isSuccess = success;
}
public Boolean getSuccess() {
return isSuccess;
}
}
class Model2 {
private Boolean success;
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
}
class Model3 {
private boolean isSuccess;
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean success) {
isSuccess = success;
}
}
class Model4 {
private boolean success;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}

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

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

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

关于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 <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> a);
public boolean is<PropertyName>();
public void set<PropertyName>(boolean m);

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

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

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

@Data
class Model3 implements Serializable {
private static final long serialVersionUID = 1836697963736227954L;
private Integer age;
private String name;
private boolean isSuccess;
private boolean isDel;
public String getUser(){
return "Hello JWZ";
}
}

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

 //定一个Model3类型
Model3 model3 = new Model3();
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 =new Gson();
System.out.println("Serializable Result With Gson :" +gson.toJson(model3));
//使用jackson(2.9.6)序列化model3成字符串并输出
ObjectMapper om = new ObjectMapper();
System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model3));

得到如下结果:

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

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

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

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

由此可以得出结论:

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

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

 

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

 public static void main(String[] args) {
Model3 model3 = new Model3();
model3.setSuccess(true);
String fastJSONString=JSON.toJSONString(model3);
System.out.println(fastJSONString);
Gson gson =new Gson();
System.out.println(gson.fromJson(fastJSONString,Model3.class));
}

 

 isSuccess竟然变为false

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

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

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

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

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

 

 

public class Test {
public static void main(String[] args) {
Model3 model3 = new Model3();
System.out.println("model3 : " + model3);
}
}
@Data
class Model3 implements Serializable {
boolean success;
Boolean del;
}

 

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

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

Boolean success;

 

 

参考:

《Java工程师成神之路》

《阿里巴巴Java开发手册》

版权声明
本文为[谁将新樽辞旧月,今月曾经照古人]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/jiangwz/p/14434957.html

  1. Add filter and execute filter in excel by Java
  2. Dialogue in spring
  3. 解决Docker MySQL无法被宿主机访问的问题
  4. Oracle OCP 19c 认证1Z0-083考试题库(第1题)
  5. Solve the problem that docker MySQL cannot be accessed by the host
  6. Oracle OCP 19C certification 1z0-083 examination question bank (question 1)
  7. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  8. Seven array methods for JavaScript you need to master in 2021
  9. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  10. Struts2 + Json _ 配置,异常解决及深入了解Struts2返回JSON数据的原理及具体应用范例
  11. Seven array methods for JavaScript you need to master in 2021
  12. Struts2 + Json _ Configuration, exception resolution and in-depth understanding of Struts2 return JSON data principle and specific application examples
  13. (三)MySQL锁机制 + 事务
  14. (3) MySQL lock mechanism + transaction
  15. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  16. Seven array methods for JavaScript you need to master in 2021
  17. 基于Kafka和Elasticsearch构建实时站内搜索功能的实践
  18. Practice of building real time search function in the website based on Kafka and elasticsearch
  19. Golang 实现 Redis(9): 使用GeoHash 搜索附近的人
  20. RxHttp - 轻量级、可扩展、易使用、完美兼容MVVM、MVC架构的网络封装类库
  21. Golang 实现 Redis(9): 使用GeoHash 搜索附近的人
  22. RxHttp - 轻量级、可扩展、易使用、完美兼容MVVM、MVC架构的网络封装类库
  23. Golang realizes redis (9): using geohash to search nearby people
  24. Rxhttp - lightweight, extensible, easy to use, perfectly compatible with MVVM, MVC architecture network encapsulation class library
  25. Golang realizes redis (9): using geohash to search nearby people
  26. Rxhttp - lightweight, extensible, easy to use, perfectly compatible with MVVM, MVC architecture network encapsulation class library
  27. 读懂框架设计的灵魂 — Java 反射机制
  28. 治疗磁盘空间不足焦虑症,释放容器占用空间——Win10+docker篇
  29. 别再用jodatime了!全网最权威Java8日期时间类LocalDate、LocalDateTime详解
  30. Understanding the soul of framework design java reflection mechanism
  31. 配置客户端以安全连接到Apache Kafka集群4:TLS客户端身份验证
  32. Treating anxiety of insufficient disk space and releasing space occupied by containers -- win10 + docker
  33. Don't use jodatime any more! The most authoritative java 8 date and time classes in the whole network: detailed explanation of localdate and localdatetime
  34. Configure clients to connect securely to Apache Kafka Cluster 4: TLS client authentication
  35. Spring break
  36. 高性能MySQL(三):Schema与数据类型优化
  37. High performance mysql (3): schema and data type optimization
  38. redis解决缓存、击穿、雪崩
  39. redis
  40. 骑士卡:基于Kafka搭建消息中心,上亿消息推送轻松完成
  41. Redis solves cache, breakdown and avalanche
  42. redis
  43. Knight card: build a message center based on Kafka, and push hundreds of millions of messages easily
  44. Oracle OCP 19c 认证1Z0-083考试题库(第2题)
  45. redis的三种模式
  46. kubernetes和docker----2.学习Pod资源
  47. 谈一谈如何远程访问MySQL(腾讯云,云主机)
  48. Linux(五):Linux的文档编辑器Vi
  49. Oracle OCP 19C certification 1z0-083 examination question bank (question 2)
  50. 云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第6篇
  51. kubernetes和docker----2.学习Pod资源
  52. JSP基于Java开发Web应用程序特点有哪些?
  53. Three modes of redis
  54. Kubernetes and docker -- 2. Learning pod resources
  55. Linux (5): the document editor VI of Linux
  56. Cloud native project practice Devops (gitops) + k8s + BPF + SRE, using golang to develop production level mahjong game server from 0 to 1
  57. Kubernetes and docker -- 2. Learning pod resources
  58. What are the characteristics of JSP developing web application based on Java?
  59. Lottie error: java.lang.AssertionError : android.util.JsonReader .peek
  60. Rxhttp - lightweight, extensible, easy to use, perfectly compatible with MVVM, MVC architecture network encapsulation class library