Lombok是一款Java开发中常用的工具库,它提供了许多注解,可以简化代码的编写。其中,@Builder注解可以帮助我们快速生成Builder模式的代码,但在使用过程中,我们也需要注意一些细节,否则可能会出现一些问题。下面分享一些我在实际开发中遇到的问题,希望大家引以为戒。
1. 事件背景
在预发环境测试时,Kafka消费出现告警,经排查后发现原因是数据插入失败,一直在重试。本次在数据库中新增了字段,所以很快定位到问题出在了新字段上。
2. 排查经过
- 数据库新增字段中声明了NOT NULL,但代码在中赋了NULL值,导致插入失败;
- 进一步排查所有给新增字段赋值的代码,发现了一处lombok注解:
// 这里简化了业务类,只是为了说明情况
import lombok.Data;
@Data
public class Reason {
// ...业务字段
private String id;
@Builder
@Getter
@ToString
public static class Param {
// ...业务字段
private long type;
private String opUserName = "";
}
}
- 调用这处builder类的业务逻辑,没有为opUserName字段赋值:
@Service
public class Service {
// ...业务逻辑略
// 调用
public void call() {
// ...业务逻辑略
Reason.Param param = Reason.Param.builder().type(type);
// ...业务逻辑
}
}
3. 原因
- 在使用@Builder注解时,Lombok会为该类生成一个Builder类,该Builder类中会包含该类的所有字段,并且每个字段都有一个对应的set方法。在使用Builder类构建该类的实例时,通过调用build方法为每个字段赋值,进而调用了set方法。set方法内容大致如下:
public static class ParamBuilder {
// ...略过其他代码
// 对应的set方法,这里以reason为例子
public Param.ParamBuilder opUserName(String opUserName) {
this.opUserName = opUserName;
return this;
}
}
- 在Build时,Lombok会执行对应的set方法,但方法中没有为默认值做特殊处理。因此如果在build时没有肤质,则会默认赋NULL值覆盖,因此导致最终返回NULL;
4. 解决方案
为了避免这样问题的出现,我们可以采取以下措施:
- 在使用@Builder注解时,尽量不要为字段设置默认值,而是在Builder.build()方法中为所有字段都赋值。
- 如果必须为字段设置默认值,那么在Builder.build()方法中也要为该字段赋值,以确保不会出现null值。
- 在数据库设计时,尽量避免使用NOT NULL声明,或在代码中对所有字段进行非空判断,避免出现空指针异常。
总之,最终还是有惊无险的解决了问题,还好是预发环境。