本文已参与「新人创作礼」活动,一起开启掘金创作之路。
本文涉及的内容主要是:
- SerializerFeature枚举类
- @JSonField的使用
- @JSonType的使用
1.SerializerFeature枚举类
SerializerFeature枚举类的作用在于设置java对象转换为JSON字符串时相关的参数。SerializerFeature枚举类的的常量用作序列化的个性需求。 JSON静态方法,toJSONStrinf(),方法的第一个参数是要序列化的对象,第二个参数(可选)是SerializerFeature枚举类型的可变参数。如果各位同学忘记了JSON静态方法的话,可以参考此篇文章。
学习SerializerFeature枚举类,我觉得重点在于了解这个枚举类里面不同的常量放在JSON.toJSONString()的作用。大家可以参考如下表格:
| 常量 | 作用 |
|---|---|
| WriteMapNullValue | 如果输出的字段没有赋值,它会帮你加上null |
| WriteNullStringAsEmpty | 将空值替换为**""** |
| WriteNullNumberAsZero | 将数字字段为null的属性转换为0 |
| WriteNullBooleanAsFalse | 如果布尔值为null,序列化的时候帮你赋值为false |
| WriteDateUseDateFormat | 让时间数据让人们更容易读 |
| PrettyFormat | 改变数据输出格式 |
1.1 SerializerFeature.WriteMapNullValue
创建实体类
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String email;
private Date birthday;
}
大家注意下,student对象的Email字段没有设置值,空值默认不会序列化。如果你在序列化student对象的时候,加上SerializerFeature.WriteMapNullValue,如果输出的字段没有赋值,它会帮你加上null。这时可能同学们有个疑问,如果每个字段都有设置值,那么你加上SerializerFeature.WriteMapNullValue会有影响吗?答案是没有。如果你有设置值,那么SerializerFeature.WriteMapNullValue不会对你设置的值产生任何影响,你设置的值是什么,转成JSON字符串那就会是什么。
public class TestFastJson2 {
@Test
public void testWriteMapNullValue(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate());
//student.setEmail("zs@sina.com");
//方法的参数上,添加枚举类型
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteMapNullValue);
System.out.println(jsonString);
}
public Date getDate() {
Date date = new Date();
return date;
}
}
实验结果:
重点看email字段的值
{"age":20,"birthday":1661678276996,"email":null,"id":1,"name":"张三"}
1.2 SerializerFeature.WriteNullStringAsEmpty
这个枚举类常量的作用是将空值替换为""。student对象的Email字段还是没有设置值。如果转换为JSON字符串的对象的属性没有空值,那么设置的SerializerFeature.WriteNullStringAsEmpty不起作用。 注意:
@Test
public void testWriteNullStringAsEmpty(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate());
//student.setEmail("zs@sina.com");
//方法的参数上,添加枚举类型
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteNullStringAsEmpty);
System.out.println(jsonString);
}
实验结果:
重点看email字段的值
{"age":20,"birthday":1661680976193,"email":"","id":1,"name":"张三"}
1.3 SerializerFeature.WriteNullNumberAsZero
SerializerFeature.WriteNullNumberAsZero的作用是将数字字段为null的属性转换为0。大家注意下,在这个例子里面student的age字段没有赋值,所以是null,空值是不会被序列化的。因为在序列化student对象的时候,加了SerializerFeature.WriteNullNumberAsZero,所以你可以看到结果的age的值是0。
这时可能有同学有疑问,那就是如果student对象的email字段也不赋值呢,email字段会不会也变成0?答案是不会。因为email字段在类中的数据类型是String。你把age的数据类型改为Float,Double,亦或是Long,SerializerFeature.WriteNullNumberAsZero依然还会生效,给你赋值0。
@Test
public void testWriteNullNumberAsZero(){
Student student = new Student();
student.setId(1);
student.setName("张三");
//student.setAge(20);
student.setBirthday(getDate());
student.setEmail("zs@sina.com");
//方法的参数上,添加枚举类型
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteNullNumberAsZero);
System.out.println(jsonString);
}
实验结果:
重点看age字段的值
{"age":0,"birthday":1661682112066,"email":"zs@sina.com","id":1,"name":"张三"}
1.4 SerializerFeature.WriteNullBooleanAsFalse
SerializerFeature.WriteNullBooleanAsFalse的作用是如果布尔值为null,序列化的时候帮你赋值为false。
我们改造下Student类,其实就是在加上一个布尔值的属性
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String email;
private Date birthday;
private Boolean flag;
}
注意:flag是布尔类型,我们这里没有赋值
@Test
public void testWriteNullBooleanAsFalse(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate());
student.setEmail("zs@sina.com");
//student.setFlag(true);
//方法的参数上,添加枚举类型
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteNullBooleanAsFalse);
System.out.println(jsonString);
}
实验结果
重点看flag字段
{"age":20,"birthday":1661682886895,"email":"zs@sina.com","flag":false,"id":1,"name":"张三"}
1.5 SerializerFeature.WriteDateUseDateFormat和SerializerFeature.PrettyFormat
SerializerFeature.WriteDateUseDateFormat的作用就是让时间数据让人们更容易读,SerializerFeature.PrettyFormat改变数据输出格式。
@Test
public void testWriteDateUseDateFormat_(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate());
student.setEmail("zs@sina.com");
//student.setFlag(true);
//方法的参数上,添加枚举类型
String jsonString = JSON.toJSONString(student,SerializerFeature.WriteDateUseDateFormat,SerializerFeature.PrettyFormat);
System.out.println(jsonString);
}
实验结果:
重点关注birthday字段 没加枚举常量
{"age":20,"birthday":1661683422623,"email":"zs@sina.com","id":1,"name":"张三"}
只加了枚举常量SerializerFeature.WriteDateUseDateFormat
{"age":20,"birthday":"2022-08-28 18:46:02","email":"zs@sina.com","id":1,"name":"张三"}
加了枚举常量SerializerFeature.WriteDateUseDateFormat和SerializerFeature.PrettyFormat
{
"age":20,
"birthday":"2022-08-28 18:48:46",
"email":"zs@sina.com",
"id":1,
"name":"张三"
}
2.@JSonField的使用
该注解作用于方法上,字段上和参数上,可在进行序列化和反序列化时进行个性功能定制。
学习这个注解,重要的是学习它里面的属性:
- 注解属性name,指定序列化后的名字。name值应该在此类中唯一
- 注解属性ordinal,指定序列化后的字段顺序 属性值越小,顺序越靠前
- 注解属性format,指定序列化后的格式
- 注解属性serialize,指定是否序列化该字段,默认是true
- 注解属性deserialize,指定是否反序列化该字段
- 注解属性serialzeFeatures序列化时的特性定义(就是上面的SerializerFeature枚举类)
@Data
public class Student {
private Integer id;
//@JSONField 注解属性name,指定序列化后的名字。name值应该在此类中唯一
//@JSONField 注解属性ordinal,指定序列化后的字段顺序 属性值越小,顺序越靠前
@JSONField(name = "studentName",ordinal = 1)
private String name;
@JSONField(ordinal = 2)
private Integer age;
//@JSONField 注解属性serialize,指定是否序列化该字段,默认是true
@JSONField(serialize = false)
private String email;
//@JSONField 注解属性format指定序列化后的格式
@JSONField(format = "YYYY-MM-dd")
private Date birthday;
private Boolean flag;
}
public class TestFastJson3 {
@Test
public void testObjectToJson() {
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate());
student.setEmail("zs@sina.com");
String jsonString = JSON.toJSONString(student);
System.out.println(jsonString);
}
public Date getDate() {
Date date = new Date();
return date;
}
}
实验结果:
这是未加注解的运行结果
{"age":20,"birthday":1661684413960,"email":"zs@sina.com","id":1,"name":"张三"}
这是在student实体类的name属性上加了@JSONField(name = "studentName")的运行结果,你会发现原来的name被替换为studentName
{"age":20,"birthday":1661684632294,"email":"zs@sina.com","id":1,"studentName":"张三"}
这是在student实体类的name属性和age属性上分别添加@JSONField(name = "studentName",ordinal = 1)和@JSONField(ordinal = 2)之后的结果,你会发现studentName排在age前面
{"birthday":1661685405536,"email":"zs@sina.com","id":1,"studentName":"张三","age":20}
这是在student实体类的birthday属性上添加@JSONField(format = "YYYY-MM-dd")后的运行结果
{"birthday":"2022-08-28","email":"zs@sina.com","id":1,"studentName":"张三","age":20}
这是在student实体类的email属性上添加@JSONField(serialize = false)后的运行结果。email没有被序列化。
{"birthday":"2022-08-28","id":1,"studentName":"张三","age":20}
3.@JSonType的使用
该注解作用于类上,对该类的字段进行序列化和反序列化时的特性功能定制。这个注解的属性功能如下:
- 注解的属性includes,要被序列化的字段
- 注解的属性includes,要被序列化的字段的顺序
- 注解属性serialzeFeatures,和前面内容一样,不再赘述
实体类
@JSONType(includes = {"id","name","age","address"},orders = {"name","age","address","id"})
public class Person {
private int id;
private String name;
@JSONField(serialize = true)
private int age;
private String address;
}
public class TestFastJson4 {
@Test
public void test() {
Person person = new Person();
person.setId(1);
person.setAddress("北京市");
person.setName("张三");
person.setAge(22);
String jsonString = JSON.toJSONString(person);
System.out.println(jsonString);
}
}
实验结果:
实体类未加任何注解
{"address":"北京市","age":22,"id":1,"name":"张三"}
在实体类上指定@JSONType(includes = {"id","name","address"}),你会发现age属性没有被序列化。
{"address":"北京市","id":1,"name":"张三"}
这时可能有同学有疑问,如果在类上这样写@JSONType(includes = {"id","name","address"}),但是又在实体类的age属性上加上@JSONType(includes = {"id","name","address"}),那么age属性还会被序列化吗?答案是不会。结果如下
{"address":"北京市","id":1,"name":"张三"}
在实体类上,添加@JSONType(includes = {"id","name","age","address"},orders = {"name","age","address","id"}),运行结果如下。你会发现对比上面的结果,实体类序列的顺序改变了。
{"name":"张三","age":22,"address":"北京市","id":1}