FastJson的枚举类和常用注解

1,995 阅读7分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

本文涉及的内容主要是:

  1. SerializerFeature枚举类
  2. @JSonField的使用
  3. @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的使用

该注解作用于方法上,字段上和参数上,可在进行序列化和反序列化时进行个性功能定制。

学习这个注解,重要的是学习它里面的属性:

  1. 注解属性name,指定序列化后的名字。name值应该在此类中唯一
  2. 注解属性ordinal,指定序列化后的字段顺序 属性值越小,顺序越靠前
  3. 注解属性format,指定序列化后的格式
  4. 注解属性serialize,指定是否序列化该字段,默认是true
  5. 注解属性deserialize,指定是否序列化该字段
  6. 注解属性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的使用

该注解作用于类上,对该类的字段进行序列化和反序列化时的特性功能定制。这个注解的属性功能如下:

  1. 注解的属性includes,要被序列化的字段
  2. 注解的属性includes,要被序列化的字段的顺序
  3. 注解属性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}