jackson 序列化_jackson序列化与反序列化的应用实践

作者 | zhouweixin

来源 | urlify.cn/iEbiAz

66套java从入门到精通实战课程分享

1 相关概念

  1. 序列化: 把对象转换为字节序列的过程称为对象的序列化
  2. 反序列化: 把字节序列恢复为对象的过程称为对象的反序列化

2 序列化的作用

  1. 用于把内存中的对象状态保存到一个文件中或者数据库中
  2. 用于网络传送对象
  3. 用于远程调用传输对象

3 准备序列化对象

准备了两个类, 教师类和学生类, 其中一个学生只有一个教师
这里省略了构造方法和setter, getter方法

Teacher.java

public class Teacher {    private String name;    private Integer age;}

Student.java

package org.zwx;public class Student {    private String name;    private Integer age;    private Sex sex;    private String fatherName;    private Date bornTime;    private Teacher teacher;}

Sex.java

public enum Sex {    MALE("男"), FEMALE("女");    private String name;        Sex(String name) {        this.name = name;    }    public String getName() {        return name;    }}

4 引入jackson依赖

本示例是基于gradle的, 从maven中心仓库中选择了2.11.2版本的jackson-databind

compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.2'

5 序列化与格式化输出

5.1 流程

  1. 首先需要有一个待序列化对象, 本例中的student对象
  2. 创建一个对象映射器, jackson包下的ObjectMapper
  3. 调用序列化函数, 本例中的writeValueAsString, 将对象转为字符串, 便于展示

5.2 代码

public void testSerializable() throws IOException {    Student student1 = new Student("小明", 18, Sex.MALE, "王富贵", new Date(), new Teacher("李老师", 40));    Student student2 = new Student("小花", 16, Sex.FEMALE, "钱很多", new Date(), new Teacher("赵老师", 38));    List students = new ArrayList<>();    students.add(student1);    students.add(student2);    ObjectMapper mapper = new ObjectMapper();    String s = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(students);    System.out.println(s);}

5.3 结果

[ {  "name" : "小明",  "age" : 18,  "sex" : "MALE",  "fatherName" : "王富贵",  "bornTime" : 1599996926917,  "teacher" : {    "name" : "李老师",    "age" : 40  }}, {  "name" : "小花",  "age" : 16,  "sex" : "FEMALE",  "fatherName" : "钱很多",  "bornTime" : 1599996926917,  "teacher" : {    "name" : "赵老师",    "age" : 38  }} ]

5.4 分析

  1. 示例中调用了方法writerWithDefaultPrettyPrinter, 美化了json的格式
  2. 否则将打印
  3. [{"name":"小明","age":18,"sex":"MALE","fatherName":"王富贵","bornTime":1599997061097,"teacher":{"name":"李老师","age":40}},{"name":"小花","age":16,"sex":"FEMALE","fatherName":"钱很多","bornTime":1599997061097,"teacher":{"name":"赵老师","age":38}}]

6 自定义序列化的名字

6.1 场景

假如需要将序列化的json由驼峰命名修改为下划线命名, 如fatherName修改为father_name

只需要在字段fatherName上用注解JsonProperty配置

6.2 示例代码

@JsonProperty("father_name")private String fatherName;@JsonProperty("born_time")private Date bornTime;

6.3 示例结果

[ {  "name" : "小明",  "age" : 18,  "sex" : "MALE",  "teacher" : {    "name" : "李老师",    "age" : 40  },  "father_name" : "王富贵",  "born_time" : 1599997157609}, {  "name" : "小花",  "age" : 16,  "sex" : "FEMALE",  "teacher" : {    "name" : "赵老师",    "age" : 38  },  "father_name" : "钱很多",  "born_time" : 1599997157610} ]

7 自定义输出格式

7.1 bornTime格式设置

当前bornTime的格式为unix时间戮, 可读性非常差

现修改为yyyy-MM-dd HH:mm:ss
并设置时区为东八区

示例代码

@JsonProperty("born_time")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date bornTime;

结果

[ {  "name" : "小明",  "age" : 18,  "sex" : "MALE",  "teacher" : {    "name" : "李老师",    "age" : 40  },  "father_name" : "王富贵",  "born_time" : "2020-09-13 19:50:47"}, {  "name" : "小花",  "age" : 16,  "sex" : "FEMALE",  "teacher" : {    "name" : "赵老师",    "age" : 38  },  "father_name" : "钱很多",  "born_time" : "2020-09-13 19:50:47"} ]

7.2 sex设置为中文

只需要为Sex添加一个方法getOrdinal, 并添加注解JsonValue即可

示例代码

@JsonValuepublic String getOrdinal() {    return name;}

示例结果

[ {  "name" : "小明",  "age" : 18,  "sex" : "男",  "teacher" : {    "name" : "李老师",    "age" : 40  },  "father_name" : "王富贵",  "born_time" : "2020-09-13 19:57:47"}, {  "name" : "小花",  "age" : 16,  "sex" : "女",  "teacher" : {    "name" : "赵老师",    "age" : 38  },  "father_name" : "钱很多",  "born_time" : "2020-09-13 19:57:47"} ]

7.3 sex设置为序号

有些场景喜欢用0和1等序号设置男女, 即枚举的序号: 0表示男, 1表示女

此时需要修改Set的getOrdinal方法

  1. 修改返回值类型为int
  2. 调用父类的getOrdinal方法

示例代码

@JsonValuepublic int getOrdinal() {    return super.ordinal();}

示例结果

[ {  "name" : "小明",  "age" : 18,  "sex" : 0,  "teacher" : {    "name" : "李老师",    "age" : 40  },  "father_name" : "王富贵",  "born_time" : "2020-09-13 20:01:44"}, {  "name" : "小花",  "age" : 16,  "sex" : 1,  "teacher" : {    "name" : "赵老师",    "age" : 38  },  "father_name" : "钱很多",  "born_time" : "2020-09-13 20:01:44"} ]

8 拍平嵌套类型

场景

如前面提到的结果所示, teacher的两个属性并不在student的第一层,
有时可能会更深的层次, 使用起来不太友好

如何用teacher_name和teacher_age两个属性代替teacher呢?

  1. 在Student的teacher属性上添加注解JsonUnwrapped, 意为不包裹
  2. 在Teacher的属性上利用注解JsonProperty重命名

示例代码

Student.java

@JsonUnwrappedprivate Teacher teacher;

Teacher.java

@JsonProperty("teacher_name")private String name;@JsonProperty("teacher_age")private Integer age;

示例结果

[ {  "name" : "小明",  "age" : 18,  "sex" : 0,  "teacher_name" : "李老师",  "teacher_age" : 40,  "father_name" : "王富贵",  "born_time" : "2020-09-13 20:21:53"}, {  "name" : "小花",  "age" : 16,  "sex" : 1,  "teacher_name" : "赵老师",  "teacher_age" : 38,  "father_name" : "钱很多",  "born_time" : "2020-09-13 20:21:53"} ]

9 自定义序列化器

9.1 场景

假如需要将年龄调整为理论学龄, 即将年龄减去7, 得到理论学龄, 如何操作呢?

  1. 创建自定义年龄序列化器AgeSerializer, 继承StdSerializer<>
    1. 创建AgeSerializer的构造方法
    2. 重写serialize函数
  2. 利用注解修指定Student属性age的序列化器AgeSerializer

9.2 示例代码

AgeSerializer.java

public class AgeSerializer extends StdSerializer {    protected AgeSerializer() {        super(Integer.class);    }    @Override    public void serialize(Integer value, JsonGenerator gen, SerializerProvider provider) throws IOException {        gen.writeNumber(value - 7);    }}

Student.java

@JsonSerialize(using = AgeSerializer.class)private Integer age;

9.3 示例结果

[ {  "name" : "小明",  "age" : 11,  "sex" : 0,  "teacher_name" : "李老师",  "teacher_age" : 40,  "father_name" : "王富贵",  "born_time" : "2020-09-13 20:31:59"}, {  "name" : "小花",  "age" : 9,  "sex" : 1,  "teacher_name" : "赵老师",  "teacher_age" : 38,  "father_name" : "钱很多",  "born_time" : "2020-09-13 20:31:59"} ]

10 反序列化

10.1 流程

  1. 首先需要有序列化好的数据, 可以是string, byte[], 文件二进制等
  2. 创建一个对象映射器, jackson包下的ObjectMapper
  3. 调用反序列化函数, 本例中的readValue, 将字符串转为对象

10.2 反序列化对象数据

示例代码

public void testDeserializable() throws JsonProcessingException {    String s = "{"name":"小明","age":11,"sex":0,"teacher_name":"李老师","teacher_age":40,"father_name":"王富贵","born_time":"2020-09-13 20:46:10"}";    ObjectMapper mapper = new ObjectMapper();    Student student = mapper.readValue(s, Student.class);    System.out.println(student);}

示例结果

Student{name='小明', age=11, sex=MALE, fatherName='王富贵', bornTime=Sun Sep 13 20:46:10 CST 2020, teacher=Teacher{name='李老师', age=40}}

分析

  1. 为了便于打印对象数据, 重写了Student和Teacher的toString方法
  2. 从数据中可以看出, age的结果是错误的, 原因在于之前自定义的序列化器将年龄减小了7, 10.4节将会通过自定义反序列化器来解决此问题

10.3 反序列化对象数组数据

示例代码

public void testDeserializableStudents() throws JsonProcessingException {    String s = "[{"name":"小明","age":11,"sex":0,"teacher_name":"李老师","teacher_age":40,"father_name":"王富贵","born_time":"2020-09-13 20:51:31"},{"name":"小花","age":9,"sex":1,"teacher_name":"赵老师","teacher_age":38,"father_name":"钱很多","born_time":"2020-09-13 20:51:31"}]";    ObjectMapper mapper = new ObjectMapper();    Student[] students = mapper.readValue(s, Student[].class);    for (Student student : students) {        System.out.println(student);    }}

示例结果

Student{name='小明', age=11, sex=MALE, fatherName='王富贵', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='李老师', age=40}}Student{name='小花', age=9, sex=FEMALE, fatherName='钱很多', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='赵老师', age=38}}

分析

  1. readValue的第二个参数需要传类型, 这里推荐用数组, 不推荐用List, 具体原因笔者目前也没花时间去研究

10.4 自定义反序列化器

从10.2节及10.3的现象中可以看出来, 仅仅自定义的序列化器会导致序列化的过程是正常的, 反序列化的过程仍然是默认逻辑, 有时候会导致意想不到的结果

遇到此场景, 可以考虑自定义反序列化器

  1. 创建自定义反序列化器AgeDeserializer, 继承StdDeserializer<>
  2. 重写deserialize方法
  3. 在Student的age属性上添加注解JsonDeserialize, 并指定反序列化器AgeDeserializer

示例代码

AgeDeserializer.java

public class AgeDeserializer extends JsonDeserializer {    @Override    public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {        return p.getIntValue() + 7;    }}

Student.java

@JsonSerialize(using = AgeSerializer.class)@JsonDeserialize(using = AgeDeserializer.class)private Integer age;

示例结果

Student{name='小明', age=18, sex=MALE, fatherName='王富贵', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='李老师', age=40}}Student{name='小花', age=16, sex=FEMALE, fatherName='钱很多', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='赵老师', age=38}}

11 注解JsonInclude

该注解使用在实体类上, 格式@JsonInclude(value = JsonInclude.Include.NON_DEFAULT)

其中, Include有7种参数, 功能对比如下

参数功能备注Include.ALWAYS属性总是序列化(需要有get方法)默认值Include.NON_DEFAULT属性为默认值不序列化如: int:0, bool:falseInclude.NON_EMPTY属性为空("")或null不序列化
Include.NON_NULL属性为null不序列化
Include.CUSTOM
Include.USE_DEFAULTS
Include.NON_ABSENT

代码示例

Student.java

@JsonInclude(value = JsonInclude.Include.NON_DEFAULT)public class Student {
public void testNonDefault() throws IOException {    Student student = new Student("", 0, null, null, null, null);    ObjectMapper mapper = new ObjectMapper();    String s = mapper.writeValueAsString(student);    System.out.println(s);}

示例输出

{  "name" : "",  "age" : -7}

分析

  1. 当属性为默认值, 即零值时, 不序列化
  2. 常见的零值:
    1. int: 0
    2. bool: false,
    3. String: null

12 注解JsonIgnoreProperties

该注解为类注解, 配置忽略序列化和反序列化的字段名
如下所示, 忽略字段name和age

@JsonIgnoreProperties(value = {"name", "age"})@JsonInclude(value = JsonInclude.Include.NON_DEFAULT)public class Student {

13 注解JsonIgnore

该注解为属性注解, 表示忽略当前属性, 如下所示, 表示忽略name字段

@JsonIgnoreprivate String name;
79af4d5a25a3826b5838f4019c448ca7.png
@JsonIgnoreprivate String name;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/244418.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java mqtt客户端_基于 t-io 实现一个 mqtt5 协议之 mica-mqtt

一、简介 MQTT 全称为 Message Queuing Telemetry Transport&#xff08;消息队列遥测传输&#xff09;是一种基于发布/订阅范式的“轻量级”消息协议&#xff0c;由 IBM 发布。目前使用比较广泛的就是 mqtt 3.1.1&#xff08;2014年制定&#xff09;&#xff0c;mqtt 5.0&…

java自我介绍_JAVA面试技巧之自我介绍

【如何进行自我介绍】自我介绍这个问题&#xff0c;不用多说了&#xff0c;面试必定会问&#xff01;如果想要在自我介绍的时候就能够打动面试官&#xff0c;吸引面试官对我们的兴趣&#xff0c;那么像我们这种接受过Java培训的程序员的自我介绍当然不能和应届生或者其他非技术…

java excel 操作 poi_Java使用apache poi进行excel相关操作

一.基本介绍1.1、Apache POI介绍Apache POI是一个可以进行微软的文档进行开源库&#xff0c;可以操作的文档类型包括word、ppt、excel、visio、outlook....本文主要针对Apache POI对excel的操作进行介绍&#xff0c;主要包括如何创建一个excel、录入数据、读取excel数据的方式。…

程序解析excel中的图片_产品日志丨支持导入Excel中的图片amp;批量修改后期实体字段...

本次安捷秀又迎来了一个大版本更新&#xff0c;除了大家呼声很高的「实体模块导入 Excel 」外&#xff0c;还有「批量编辑实体」&#xff0c;「支持右击修改」以及针对海外用户的「全页面支持英文」等功能的新增与优化&#xff0c;一起来看看吧。导入功能优化AGILESHOT&#xf…

java不同垃圾回收器_细述 Java垃圾回收机制→Types of Java Garbage Collectors

本文非原创&#xff0c;翻译自Types of Java Garbage Collectors在Java中为对象分配和释放内存空间都是由垃圾回收线程自动执行完成的。和C语言不一样的是Java程序员不需要手动写垃圾回收相关的代码。这是使得Java如此流行&#xff0c;同时也是Java能帮助程序员写出更好的Java应…

js修改地址栏url_不同寻常的地址栏过渡

前几天&#xff0c;我在推特上看到这样一张图。原来地址栏还能这么玩&#xff0c;瞬间就觉得自己弱爆了。然后我决定去实现一下这个效果&#xff0c;然后做成一个库。画了一个晚上&#xff0c;终于做好了。这是最后的成果。这个库使用非常的简单。你只需要&#xff0c;yarn add…

kaggle数据集_ArXiv170万篇论文数据集上线Kaggle!

大数据文摘出品学术圈的朋友对ArXiv肯定都不陌生。在将近30年的时间里&#xff0c;ArXiv通过公开访问学术文章为公众和研究社区提供了一个更高效的学术成果沟通平台&#xff0c;从物理学到计算机科学的许多子学科&#xff0c;以及介于两者之间的所有内容&#xff0c;包括数学&a…

万能驱动xp离线版_教你用SC封装软件来封装XP系统

今天我们来讲解一下如何用SC软件来封装XP系统。今天的讲解只演示基本的SC封装软件&#xff0c;具体的封装前的准备工具&#xff0c;我们不进行讲解&#xff0c;当然前期的准备工作也是有很多&#xff0c;首先我们先要安装虚拟机软件&#xff0c;并在虚拟机上面安装好原版的XP系…

java dispo lock_java实现文件上传和下载(1)

原理&#xff1a; 使用html 的 标签&#xff0c;提交form 的几个属性必须为&#xff1a; methodpost encTypemultipart/form-data;组件:smartUpload或者commons fileuploadsmartUpload代码实现1。文件预览function showImage(obj){var strobj.value;$("#id").html(&q…

剪板机自动上下料_机器人联轴器,用于机器人自动化上下料

关注点击蓝字&#xff0c;关注我吧纤薄型机器人联轴器&#xff0c;可搬运重量范围从 1kg 至 1,000kg&#xff0c;用于高效机器人自动化机床上下料&#xff0c;多年来受到广泛认可。紧凑型微型联轴器适合于最近迅速发展的小型机器人应用领域。无人操作时工艺可靠性高模块的特殊混…

java 格式化 布尔型_Java基础篇(1)-格式化

本文目录&#xff1a;十进制数字格式化——DecimalFormat数字格式化基类——NumberFormat字符串格式化类——String.format()Linux输出格式化——printf1. 十进制数字格式化(DecimalFormat)decimal是对数字进行格式化&#xff0c;比如取2位小数&#xff0c;这是最常见的。Java提…

一旦有辞职念头就干不长了吗_每天都有辞职不想上班的冲动,你有吗?

我从大学毕业到今天&#xff0c;工作的时间将近10年了。直到现在&#xff0c;我还经常有辞职的想法。我觉得现在职场真的不好混&#xff0c;不如意的事情十之八九&#xff0c;有了辞职冲动是非常正常的&#xff0c;不必一上来就刻意的否定&#xff0c;或者克制。依照我的职场经…

mysql 序号_脚本搭建Nginx、Redis、MySql、Maven

当你面对一个全新的Linux系统时&#xff0c;是如何部署搭建项目环境呢&#xff1f;是否是一个一个软件安装呢&#xff1f;小编在往期文章中介绍了相关软件的安装方法&#xff0c;但是你是否发现不同的软件安装下来是否会出现问题呢&#xff1f;今天就教大家如何使用脚本一键安装…

mysql数据库子查询的使用_MySQL数据库使用子查询方式更新数据优化及思考

【环境介绍】云数据库MySQL 5.7【背景描述】业务需要&#xff1a;需要对16370077的表数据进行更新部分数据操作UPDATE P_MOXXXX_REXXXX SET FISAVAILABLE 1 WHERE FREG_ID IN (SELECT FREG_ID FROM P_MOXXXX_REXXXX_UPDATE_TEMP);【按照正常流程更新数据操作】使用archery的SQ…

业务中台建设与应用_容易网业务中台建设,助力企业数字化转型

“中台”这个概念自去年流行以来&#xff0c;至今仍然搅动着市场。期间&#xff0c;既有阿里、腾讯、百度、字节跳动、美团、滴滴等等头部互联网企业刮起的转型风&#xff0c;也有茅台延后中台签约、服装品牌CIO被开除等风波。尽管存在争议&#xff0c;但这不影响越来越多的企业…

java由大到小输出整数xvz_【视频+图文】Java经典基础练习题(三):输入3个整数,并将其由小到大输出...

java经典实例书店书畅想畅销书109.6元包邮(需用券)去购买 >目录https://www.cnblogs.com/Qpgshare/p/12588923.html一、视频讲解https://www.cnblogs.com/Qpgshare/p/12588923.html二、思路分析https://www.cnblogs.com/Qpgshare/p/12588923.html总结&#xff1a;https://ww…

压力测试过负载均衡_性能测试的方法有哪些?

压力测试&#xff1a;压力测试的关键字就是“极端”。通过对系统的极端加压&#xff0c;从而观察系统的所表现出来性能问题。再对此性能问题进行分析&#xff0c;从而达到系统优化的目的。所以压力测试就是一定要让系统出问题&#xff0c;如果系统没有出问题&#xff0c;那么压…

java比ios慢_Android为什么比iOS慢

有些人会觉Android应用没有iOS应用使用得流畅&#xff0c;我觉得主要原因有以下几点&#xff1a;第一&#xff0c;因为Android平台相较于iOS起步晚&#xff0c;平台不成熟&#xff0c;初期的开发者水平也有限&#xff0c;没有很关注性能优化&#xff0c;只是想做出可用的应用&a…

output怎么用_如何用 C++ 写一个可编程软件渲染器?

今天你想用最新的 D3D12 画一个三角形&#xff0c;少说也要上千行代码了&#xff0c;对于初学者来讲&#xff0c;这个门槛是非常高的&#xff0c;太多干扰了&#xff0c;而一千多行代码&#xff0c;已经足够你重头实现一个简易版 D3D 了&#xff0c;为什么不呢&#xff1f;比起…

mysql delete语句_MySQL ------ 触发器(TRIGGER)(二十七)

MySQL 语句在需要时被执行&#xff0c;存储过程也是&#xff0c;但是你要是想要某条&#xff08;或某些语句&#xff09;在事件发生时自动执行&#xff0c;该怎么办触发器由此而来触发器&#xff1a;某个表发生更改时自动处理。触发器是MySQL响应delete&#xff0c;insert&…