Loading

@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
}

posted @ 2021-04-22 14:19  硝酸铜  阅读(364)  评论(0编辑  收藏  举报