作者 | 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;
@JsonIgnoreprivate String name;

jackson 序列化_jackson序列化与反序列化的应用实践相关推荐

  1. baseresponse响应类_内部类、响应类Response、序列化基类、反序列化、全局局部钩子...

    一.内部类 1.概念:将类定义在一个类的内部,被定义的类就是内部类 2.特点:内部类及内部类的所以名称空间,可以直接被外部类访问的 3. 应用:通过内部类的名称空间,给外部类额外拓展一些特殊的属性(配 ...

  2. 序列化_SpreadJS序列化与反序列化表格Serialization+Deserialization

    前言 SpreadJS表格控件有着很强大的功能:序列化与反序列化表格.熟练使用该功能达到加快开发进度,减少代码量,降低业务逻辑复杂度,处理一些特殊逻辑需求等效果. 功能使用介绍: 序列化: 通过序列化 ...

  3. 魔方APP项目-04-用户模块API接口、Marshmallow,基本构造器(Schema),Schema数据序列化、Schema数据反序列化、反序列化对数据验证、模型构造器(ModelSchema)

    用户模块 当前开发的项目属于社交类型项目,所以关于用户的信息和功能直接贯穿了整个项目.所以此处实现用户模块功能,我们先把用户基本信息构建起来,并通过基本信息实现用户注册登录相关功能,后面遇到业务再继续 ...

  4. java byte序列化,java对象序列化byte[] and byte[]反序列化对象--转

    import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOExceptio ...

  5. 对象序列化流与对象反序列化流(ObjectOutputStream,ObjectInputStream)

    这个连接包含了常用的流------IO流(总篇章) 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型.对象的数据和对象中存 ...

  6. java c 序列化_Java 序列化

    序列化(对象写入文件)   反序列化(从文件读取对象) public class Demo01 { public static void main(String[] args) throws IOEx ...

  7. java map 实现 序列化,MapReduce序列化

    序列化就是把内存中的对象转换成字节序列以便于存储到磁盘(持久化)和网络传输. 反序列化就是将字节序列或者是持久化的数据转换成内存中的对象. 内存中的对象只能本地进程使用,断掉后就消失了,也不能被发送到 ...

  8. android对象序列化,Android序列化总结

    前言 公园里,一位仙风鹤骨的老者在打太极,一招一式都仙气十足,一个年轻人走过去:"大爷,太极这玩意儿花拳绣腿,你练它干啥?"老者淡淡一笑:"年轻人,你还没有领悟到太极的真 ...

  9. java实现序列化_java 序列化实现方式总结

    什么是序列化,可能大家都知道,但又不很清楚,呵呵,就像我一样,下面是一段百度百科的说明,说的很清楚,可以参考下 序列化 (serialization) 将对象的状态信息转换为可以存储或传输的窗体的过程 ...

最新文章

  1. 以人为本的机器学习:谷歌人工智能产品设计概述 By 机器之心2017年7月17日 12:13 取代了手动编程,机器学习(ML)是一种帮助计算机发现数据中的模式和关系的科学。对于创建个人的和动态的经历
  2. python知识:NetworkX初步
  3. 【Android应用保护技术探索之路系列】之一:Android应用保护技术开篇
  4. matlab求解复数方程组,【求解】matlab求解非齐次方程组,但是系数矩阵是复数,求帮忙...
  5. 好程序员Java分享SQL语言之索引
  6. 从MongoDB GridFS流式传输文件
  7. C++中的inline用法
  8. New directions in automated traffic analysis论文解读
  9. Android浮窗权限研究(转载)
  10. 数据结构专题(二):2.4链表的插入操作,头插法
  11. 再见,中国移动 3G!
  12. 被3整除判断准则的证明
  13. java File_encoding属性
  14. mac启动rabbitmq_从0到1学习Flink—— Flink 读取 Kafka 数据写入到 RabbitMQ
  15. 毕业论文自动去重软件,内附软件
  16. 计算机一级安装的软件要钱吗,电脑没装这5个软件,基本算是废了
  17. 当前版本与卡刷包android_Android p系统下载-MIUI 10 Android p线刷包卡刷包最新版 - 极光下载站...
  18. 百度近期开始大规模清理不良P2P网贷平台
  19. X电容Y电容如何选择与使用
  20. Marshmallow 库

热门文章

  1. mysql8.0提示命令_Mysql 8.0 相关命令
  2. java drawstring字体大小,JAVA中,drawstring 方法的用法,格式是什么啊
  3. [蓝桥杯][2018年第九届真题]迷宫与陷阱(三维数组标记BFS)
  4. TensorFlow2快速模型构建及tensorboard初体验
  5. 利用samba实现网络文件共享
  6. ffmpeg 将拆分的数据合成一帧_FFmpeg + OpenGLES 实现视频解码播放和视频滤镜
  7. linux退出大于符号,每天一个linux命令--退出符号
  8. excel设置图片自动更新_智能Excel排班表,日期自动更新,三班排班一键统计,极简轻松...
  9. python切换ip群发邮件_python获取外网IP并发邮件的实现方法
  10. bool c语言_C/C++编程笔记:C语言结构体—位域,如何指定成员变量所占Bit?