千万别乱用了!Lombok的@Data 和 @Builder 有巨坑!

点击关注公众号:互联网架构师,后台回复 2T获取2TB学习资源!

上一篇:Alibaba开源内网高并发编程手册.pdf

问题背景

Lombok使⽤ 同时使⽤@Data和@Builder ,构建无参构造器报错!编译不通过。如下图:

86ba1c5fe525dc04e7854abc31dc0168.jpeg

图片

Lombok @Data和@Builder分别单独分析用法

Lombok使⽤@Data可以⽣成⽆参构造和类⾥⾯所有属性的getter/setter⽅法。可以简化我们代码的开发。(需要安装Lombok插件和引⼊Lombok依赖)。

例如下⾯的⼀个实体类,引⼊Lombok后,可以⾃动⽣成GET/SET⽅法和⽆参构造函数。

929559618bfa0aaaa6411409d3f98ed0.jpeg

编译后的class为:可以看到不仅帮我们生成了get和set ,同时也有默认的无参构造器

7f888902c244dd35fcdad27850a23858.jpeg

图片

那么怎么自动生成有参构造器呢?使用@Builder注解,将会帮助我们⽣成全属性的构造⽅法。

bd715cdfdc6139c13d1ae86c679e4406.jpeg

图片

编译后的class为:可以看到 已经帮我们构建好了全属性的构造方法,但是如果值只引用@Builder注解是无法生成get和set的。

f7a99972d38c85bf1802615c7a670d3c.jpeg

图片

但是如果同时使⽤@Data和@Builder的话,可以看出尽管⽣成了GET/SET⽅法,但是⽆参构造⽅法没有了,这显然是不能接受的,因为很多框架都会调⽤⽆参构造去创建对象。

ff4e075846d19f3669da06fe8f1aa77d.jpeg

图片

编译后的class:

5ed566f955aecaee7353407441f5df47.jpeg

我们尝试在Tet1类,⼿动添加⽆参构造⽅法。编译发现报错不通过:

2012533972292fa331a017259334f655.jpeg

图片

解决方法

方法一

Lombok同时使⽤@Data和@Builder的时候,如果要⽣成⽆参构造,需要在代码⾥⾯⼿动引⼊注解@Tolerate,让Lombok在⽣成类的时候,对指定的构造函数不感知。

807fe1086311ab661d56943b1b6ab386.jpeg

图片

方法二

直接使用无参构造器+有参构造器的方式,@RequiredArgsConstructor 来构建有参,@NoArgsConstructor来构建无参构造器,如图所示:

2af49f701ff2b9d2a194d4595d7da0b4.jpeg

编译后效果:

5580450ffebc87b68b91afa878adcb53.jpeg

图片

Lombok原理

Java的编译分为以下⼏个阶段:

解析与填充符号表->注解处理->分析与字节码⽣成->⽣成⼆进制class⽂件。

  • Lombok 使⽤的是 JDK 6 实现的 JSR 269: Pluggable Annotation Processing API (编译期的注解处理器),它是在编译期时把 Lombok 的注解代码,转换为常规的 Java ⽅法⽽实现注⼊。

  • 在编译期阶段,当 Java 源码被抽象成语法树 (AST) 之后,Lombok 会根据⾃⼰的注解处理器动态的修改AST,增加新的代码 (节点),在这⼀切执⾏之后,再通过分析⽣成了最终的字节码 (.class) ⽂件,这就是Lombok 的执⾏原理。

可以借助注解处理器实现⼀个简单的 Setter,我们的实现步骤是:

  • ⾃定义⼀个注解标签接⼝,并实现⼀个⾃定义的注解处理器;

  • 利⽤ tools.jar 的 javac api 处理 AST (抽象语法树)3. 使⽤⾃定义的注解处理器编译代码。

1.定义⾃定义注解和注解处理器

⾸先创建⼀个 MySetter.java ⾃定义⼀个注解,代码如下:

24f7823d7c59a98065ff5759a27ead3c.jpeg

图片

再实现⼀个⾃定义的注解处理器,代码如下:

55fc291f44a3672eccdda07aefced6a7.jpeg

图片

489c5ff1a003a1f81583defce2cf6ef2.jpeg

图片

1106ba6d1e3b1a6c3a7aab6dc830b9e1.jpeg

图片

测试类如下:

d26108ce3293bafdb9ceb5f25e8e5637.jpeg

图片

2.对注解处理器进⾏编译,随后使⽤注解处理器对类进⾏编译

⾸先需要先对注解处理器进⾏编译(javac -cp ⽤于引⼊第三⽅jar包进⾏编译)

c9a1cd165153e640bf4d4b6542989148.jpeg

图片

然后使⽤注解处理器对这个Person测试类进⾏编译:

这时候再看⽣成的Person.class,可以发现Setter⽅法已经⽣成了:

4e65292379c4ba2823f549bf3562e301.jpeg

图片

38ca2076561919c16588df58b9cdd871.jpeg

图片

总结

当然尽管测试类已经⽣成Setter⽅法,但是因为是在编译时期⽣成的,因此我们在开发的时候是没法直接调⽤Setter⽅法的,因此Lombok提供了插件机制,⽅便我们在开发的时候可以直接去调⽤Lombok的特性。

来源:juejin.cn/post/7103011031672176677

End-

最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

1c3e5dd1e37aab6fa223cfc311173124.png

正文结束

推荐阅读 ↓↓↓

1.求求你别在用SpringMVC了,太Low了!Spring又官宣了一个更牛逼的替代框架!

2.从零开始搭建创业公司后台技术栈

3.程序员一般可以从什么平台接私活?

4.Spring Boot+Redis+拦截器+自定义Annotation实现接口自动幂等

5.为什么国内 996 干不过国外的 955呢?

6.中国的铁路订票系统在世界上属于什么水平?                        

7.15张图看懂瞎忙和高效的区别!

59555d93a079c1af3ff4e732e2106af6.gif