天天写的Lombok @Data注解,其实藏着你没注意的天坑,很多Spring项目都踩过

做Java开发尤其是Spring Boot项目,几乎没人能躲开Lombok的@Data注解。写实体类、DTO、VO的时候往上一标,getter、setter、toString、equals、hashCode全自动生成,代码瞬间清爽大半,省下来的时间都能多喝两杯茶。但你可能不知道,这个每天都在敲的注解,其实是Spring项目里隐藏最深的“隐形坑”,不少人直到线上出现诡异的集合异常、实体比较错误,排查三天都找不到原因,才发现自己踩了大半年的雷。

今天我就结合自己在Spring生态实战里踩过的坑,把@Data最容易翻车的几个场景一次性讲透,帮你避开那些低级错误。

一、IDE看着完全正常,编译直接报cannot find symbol

很多人都遇到过这种离谱情况:代码里@Data标得好好的,IDEA完全不报红,鼠标点进去也能跳转到对应方法,一启动项目编译直接报错,提示找不到对应的getter/setter符号。

这根本不是你代码写错了,90%的情况都是开发环境配置没对齐,按下面几步排查就能解决:

    打开IDEA的Settings → Build → Compiler → Annotation Processors,一定要勾选“Enable annotation processing”,没开这个开关,Lombok根本不会在编译阶段介入生成代码

    去Plugins里确认Lombok插件已经安装并启用,很多人升级IDEA之后插件被自动禁用,直接导致注解失效

    检查Maven/Gradle依赖配置,除了引入lombok依赖,一定要把它注册为注解处理器。以Maven为例,正确的依赖配置如下:

xml

<dependency>

    <groupId>org.projectlombok</groupId>

    <artifactId>lombok</artifactId>

    <version>1.18.34</version>

    <scope>provided</scope>

</dependency>

特别提醒:JDK 17+版本一定要把Lombok升级到1.18.30以上的最新版,旧版本和高版本JDK存在兼容性问题,会直接导致注解完全失效。如果以上操作都做完还是报错,直接点File → Invalidate Caches and Restart清空IDEA缓存重启,大部分奇怪的问题都能解决。

二、继承场景下equals和hashCode直接“失灵”,集合操作全乱套

这是所有坑里面坑人最多的一个,没有之一。很多项目都习惯写一个通用的BaseEntity,把所有实体共有的id、createTime、updateTime抽出来,然后让业务实体去继承它。比如你随手写出这样的代码:

java

@Data

public class BaseEntity {

    private Long id;

    private LocalDateTime createTime;

    private LocalDateTime updateTime;

}

@Data

public class Product extends BaseEntity {

    private String name;

    private BigDecimal price;

}

然后你写一段测试逻辑,两个id完全相同的Product对象,只是商品名称和价格不一样,你以为它们逻辑上不是同一个对象,可实际运行的时候,放到HashSet里会出现重复元素,作为HashMap的key也会查找失败。

问题的根源就藏在@Data的组合注解逻辑里:它默认自带的@EqualsAndHashCode和@ToString,默认配置都是callSuper=false,生成方法的时候只会处理当前子类自己声明的字段,完全忽略从父类继承来的所有属性。上面的Product类,Lombok生成的equals方法只会比较name和price,连父类里的id字段根本不会参与判断,完全违背我们对实体相等性的判断逻辑。

修复方案非常简单,只要在子类上显式指定调用父类的属性参与计算即可:

java

@Data

@EqualsAndHashCode(callSuper = true)

@ToString(callSuper = true)

public class Product extends BaseEntity {

    private String name;

    private BigDecimal price;

}

如果你用的是JPA实体,更稳妥的做法是完全不直接用@Data,而是显式指定只使用业务主键id来生成equals和hashCode,避免其他字段变动导致对象哈希值异常:

java

@Getter

@Setter

@EqualsAndHashCode(of = "id")

@ToString

@Entity

public class User {

    @Id

    private Long id;

    private String username;

    private String email;

}

三、循环引用直接搞崩toString,日志打印直接栈溢出

很多人在写双向关联的业务类的时候,比如订单和用户的关联:Order类里持有User对象,User类里又持有Order集合。这时候直接在两个类上都标@Data,一旦你打印其中任意一个对象的日志,Lombok生成的toString方法就会无限递归调用,直接抛出StackOverflowError栈溢出。

示例场景代码:

java

@Data

public class User {

    private Long id;

    private String username;

    private List<Order> orders;

}

@Data

public class Order {

    private Long id;

    private String orderNo;

    private User user;

}

这种场景下不要无脑全字段生成toString,用@ToString.Exclude把循环引用的字段排除掉就可以完美解决:

java

@Data

public class User {

    private Long id;

    private String username;

    @ToString.Exclude

    private List<Order> orders;

}

@Data

public class Order {

    private Long id;

    private String orderNo;

    @ToString.Exclude

    private User user;

}

最后给大家总结一套Spring项目里@Data的安全使用准则

    普通POJO、DTO、VO这类没有继承关系、没有双向关联的类,可以放心直接使用@Data

    存在继承关系的实体类,必须显式加上@EqualsAndHashCode(callSuper = true)和@ToString(callSuper = true)

    数据库映射的实体类,优先单独使用@Getter、@Setter,再自定义equals和hashCode只基于主键字段生成,不要直接用全功能的@Data

    存在循环引用的类,一定要用@ToString.Exclude排除掉互相引用的字段,避免日志打印直接崩溃

很多开发者用了好几年Lombok,都没意识到@Data背后藏着这么多细节,工具越方便,我们越要搞懂它背后的运行逻辑,不然哪天线上出了诡异的问题,排查起来真的会让人怀疑人生。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容