@Accessors无法进行序列化和反序列化问题
@Accessors
: A more fluent API for getters and setters.意为:面向getter和setter的更流畅的API。所以,@Accessors是配合@Getter/@Setter注解一起使用的。
/**
* 测试用类
* @author 肖晟鹏
* @email 727901974@qq.com
* @date 2021/4/19
*/
@Data
/**
* fluent为true,生成的getter/setter为字段名,最好不要使用!否则序列化的时候会出错
* chain为true,生成链式结构的的getter/setter
*/
@Accessors(fluent = false, chain = true)
public class Person {
private Integer age;
private String name;
}
Person p = new Person();
p.setName("xcp").setAge(23);
System.out.println(p);
>>
Person(age=23, name=xcp)
为什么说最好不要使用@Accessors
注解的fluent = true
属性呢?
因为这个属性会将生成名字为字段名getter/setter,但是其本质上来说,并不是getter/setter,而是一般的访问字段的一个函数。
因为属性的getter/setter的命名格式,编译器约定为"get(is)XXX"/"setXXX",当进行序列化的时候,是通过getter/setter去访问字段的。
如果fluent = true
,就只会生成普通的函数去访问字段,没有真正意义上的getter/setter,所以会取不到值。
如果从底层来说,fluent = true
时,编译器在编译成class文件时,其字段表中的属性表为空(详细看class文件结构)。
没有getter/setter而使用生成的函数去访问字段值,序列化发生的错误示例:
@Data
@Accessors(fluent = true, chain = true)
public class Person {
private Integer age = 23;
private String name = "xcp";
}
Person p2 = new Person();
System.out.println(p2);
System.out.println(JSON.toJSONString(p2));
>>
Person(age=23, name=xcp)
{}
因为找不到其访问器getter,所以这里转换出来的是"{}"
当fluent = false
时,则不存在这个问题
@Data
@Accessors( chain = true)
public class Person {
private Integer age = 23;
private String name = "xcp";
}
Person p2 = new Person();
System.out.println(p2);
System.out.println(JSON.toJSONString(p2));
>>
Person(age=23, name=xcp)
{"age":23,"name":"xcp"}
甚至在controller中,直接返回对象,因为没有getter/setter而取不到字段值
@Data
@Accessors(fluent = true,chain = true)
public class Person{
private String name;
private int age;
public boolean isAdult(){
return this.age >= 18;
}
}
可以看到,我这里声明了两个字段,一个name
和一个age
,然后fluent = true
,其最后会生成函数名为字段名的方法来访问字段。但本质上来说却不是getter/setter。
而我们在这里定义的一个方法isAdult()
满足了编译器的约定,所以被视为一个getter,所以我们在序列化的时候,拿不到字段,反而会拿到adult
属性
Java中的属性,通常可以理解为get和set方法。而字段,通常叫做“类成员”。
@GetMapping(value = "test")
public Person test(){
return new Person().name("xcp").age(23);
}
>>
{
"adult": true
}