记录Jackson和Lombok的坑

记录Jackson和Lombok的坑

今天遇到Jackson反序列化json缺少了字段,后来研究下发现是Jackson的机制和Lombok生成的setter不一致,导致没有正确调用setter。

复现

Java实体类

@Data
public class DemoData{
    private Double t;
    private Double eDay;
}

Json字符串

{
    "t":12.23,
    "eDay":123.321
}

使用Jackson解析下来,发现只有t有值,而eDay没有解析到。

原因分析

首先第一反应是Lombok生成的getter和setter也许有问题,于是去掉@Data注解,用IDEA生成getter和setter,再进行反序列化,发现已经可以正常反序列化了。

于是看了下编译生成的代码:

public class DemoData{
    private Double t;
    private Double eDay;

    public Double getT() {
        return this.t;
    }

    public Double getEDay() {
        return this.eDay;
    }

    public void setT(final Double t) {
        this.t = t;
    }

    public void setEDay(final Double eDay) {
        this.eDay = eDay;
    }
}

去掉lombok的注解,直接用IDEA生成getter和setter,生成之后是这样的:

public class DemoData{
    private Double t;
    private Double eDay;

    public Double getT() {
        return t;
    }

    public void setT(Double t) {
        this.t = t;
    }

    public Double geteDay() {
        return eDay;
    }

    public void seteDay(Double eDay) {
        this.eDay = eDay;
    }
}

显然两边的Getter和Setter是不一样的,那么Jackson是怎么寻找属性和Setter的呢?

Jackson2在初始化序列器时,对pojo类型对象会收集其属性信息,属性包括成员变量及方法,然后属性名称和处理过后的方法名称做为key保存到一个LinkedHashMap中。
收集过程中会调用com.fasterxml.jackson.databind.util.BeanUtil中的legacyManglePropertyName方法用来处理方法名称,它会将get/set方法前缀,即get或set去掉,并将其后面的连续大写字符转换成小写字符返回。
例如: getNEWString会转变成newstring返回。你的属性名称如果有这样的"nSmallSellCount",lombok自动生成的get方法就会是这样的"getNSmallSellCount",处理过后就是这样的"nsmallSellCount",这与属性nSmallSellCount并不冲突,可以同时存在于HashMap中。

所以,当Jackson扫描由Lombok生成的POJO时,读取到setEDay,会把set去掉,拿到EDay,然后转成eday。由此导致json中的eDay属性在LinkedHashMap中没有找到setter方法,反序列化就丢失了字段。

所以原因已经确定了:当使用Lombok修饰的POJO中存在由aAxxx这样的(单个小写字母跟着大写字母)的属性时,反序列化会丢失这个字段。

如何解决

@JsonProperty

对出问题的字段添加@JsonProperty注解,并设置字段名,就可以正确解析了。

DeLombok

当代码中出现这样的字段时,由IDEA生成对应的getter和setter,会自动覆盖lombok生成的方法。

posted @ 2021-07-23 18:00  su_xtf2009  阅读(2159)  评论(0编辑  收藏  举报