一、lombok介绍
官方定义:
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量
lombok是用java语言开发的一个插件,通过自定义注解来达到简化java代码的一个类库
Lombok 能够在编译源代码期间自动帮我们生成这些方法(get/set/equals等),但并不会像反射那样降低程序的性能。
二、lombok的使用
1.在pom.xml中加入依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.4</version><scope>provided</scope> </dependency>
2.安装lombok插件
2.1 IDEA安装方式
File=>settings
安装好后重启,然后点击项目maven update,不行的话多执行几次
2.2 eclipse安装方式
下载lombok.jar包放到eclipse安装目录,再eclipse.ini配置后面加入以下内容:
-javaagent:lombok.jar -vmargs -javaagent:lombok.jar
安装好后重启,然后点击项目maven update,不行的话多执行几次
三、lombok常用的注解
1.1 @Getter and @Setter
@Getter 或 @Setter 注解作用在类或字段上,Lombok 会自动生成默认的 getter/setter 方法
- @Getter 注解
@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface Getter {// 若getter方法非public的话,可以设置可访问级别lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;AnyAnnotation[] onMethod() default {};// 是否启用延迟初始化boolean lazy() default false; }
- @Setter
@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface Setter {// 若setter方法非public的话,可以设置可访问级别lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;AnyAnnotation[] onMethod() default {};AnyAnnotation[] onParam() default {}; }
使用示例
@Getter @Setter public class GetterAndSetterDemo {String firstName;String lastName;LocalDate dateOfBirth; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class GetterAndSetterDemo {String firstName;String lastName;LocalDate dateOfBirth;public GetterAndSetterDemo() {}// 省略其它setter和getter方法public String getFirstName() {return this.firstName;}public void setFirstName(String firstName) {this.firstName = firstName;} }
1.2 @NoArgsConstructor
@NoArgsConstructor 注解可以为指定类,生成默认的构造函数
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface NoArgsConstructor {// 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法String staticName() default "";AnyAnnotation[] onConstructor() default {};// 设置生成构造函数的访问级别,默认是publicAccessLevel access() default lombok.AccessLevel.PUBLIC;// 若设置为true,则初始化所有final的字段为0/null/falseboolean force() default false; }
使用示例
@NoArgsConstructor(staticName = "getInstance") public class NoArgsConstructorDemo {private long id;private String name;private int age; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class NoArgsConstructorDemo {private long id;private String name;private int age;private NoArgsConstructorDemo() {}public static NoArgsConstructorDemo getInstance() {return new NoArgsConstructorDemo();} }
1.3 @AllArgsConstructor
使用 @AllArgsConstructor 注解可以为指定类,生成包含所有成员的构造函数,@AllArgsConstructor 注解的定义如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface AllArgsConstructor {// 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法String staticName() default "";AnyAnnotation[] onConstructor() default {};// 设置生成构造函数的访问级别,默认是publicAccessLevel access() default lombok.AccessLevel.PUBLIC; }
使用示例
@AllArgsConstructor public class AllArgsConstructorDemo {private long id;private String name;private int age; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class AllArgsConstructorDemo {private long id;private String name;private int age;public AllArgsConstructorDemo(long id, String name, int age) {this.id = id;this.name = name;this.age = age;} }
1.4 @RequiredArgsConstructor
使用 @RequiredArgsConstructor 注解可以为指定类必需初始化的成员变量,如 final 成员变量,生成对应的构造函数,@RequiredArgsConstructor 注解的定义如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface RequiredArgsConstructor {// 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法String staticName() default "";AnyAnnotation[] onConstructor() default {};// 设置生成构造函数的访问级别,默认是publicAccessLevel access() default lombok.AccessLevel.PUBLIC; }
使用示例
@RequiredArgsConstructor public class RequiredArgsConstructorDemo {private final long id;private String name;private int age; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class RequiredArgsConstructorDemo {private final long id;private String name;private int age;public RequiredArgsConstructorDemo(long id) {this.id = id;} }
1.5 @EqualsAndHashCode
使用 @EqualsAndHashCode 注解可以为指定类生成 equals 和 hashCode 方法, @EqualsAndHashCode 注解的定义如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface EqualsAndHashCode {// 指定在生成的equals和hashCode方法中需要排除的字段列表String[] exclude() default {};// 显式列出用于identity的字段,一般情况下non-static,non-transient字段会被用于identityString[] of() default {};// 标识在执行字段计算前,是否调用父类的equals和hashCode方法boolean callSuper() default false;boolean doNotUseGetters() default false;AnyAnnotation[] onParam() default {};@Deprecated@Retention(RetentionPolicy.SOURCE)@Target({})@interface AnyAnnotation {}@Target(ElementType.FIELD)@Retention(RetentionPolicy.SOURCE)public @interface Exclude {}@Target({ElementType.FIELD, ElementType.METHOD})@Retention(RetentionPolicy.SOURCE)public @interface Include {String replaces() default "";} }
使用示例
@EqualsAndHashCode public class EqualsAndHashCodeDemo {String firstName;String lastName;LocalDate dateOfBirth; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class EqualsAndHashCodeDemo {String firstName;String lastName;LocalDate dateOfBirth;public EqualsAndHashCodeDemo() {}public boolean equals(Object o) {if (o == this) {return true;} else if (!(o instanceof EqualsAndHashCodeDemo)) {return false;} else {EqualsAndHashCodeDemo other = (EqualsAndHashCodeDemo)o;if (!other.canEqual(this)) {return false;} else {// 已省略大量代码}}public int hashCode() {int PRIME = true;int result = 1;Object $firstName = this.firstName;int result = result * 59 + ($firstName == null ? 43 : $firstName.hashCode());Object $lastName = this.lastName;result = result * 59 + ($lastName == null ? 43 : $lastName.hashCode());Object $dateOfBirth = this.dateOfBirth;result = result * 59 + ($dateOfBirth == null ? 43 : $dateOfBirth.hashCode());return result;} }
1.6 @ToString
使用 @ToString 注解可以为指定类生成 toString 方法, @ToString 注解的定义如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface ToString {// 打印输出时是否包含字段的名称boolean includeFieldNames() default true;// 列出打印输出时,需要排除的字段列表String[] exclude() default {};// 显式的列出需要打印输出的字段列表String[] of() default {};// 打印输出的结果中是否包含父类的toString方法的返回结果boolean callSuper() default false;boolean doNotUseGetters() default false;boolean onlyExplicitlyIncluded() default false;@Target(ElementType.FIELD)@Retention(RetentionPolicy.SOURCE)public @interface Exclude {}@Target({ElementType.FIELD, ElementType.METHOD})@Retention(RetentionPolicy.SOURCE)public @interface Include {int rank() default 0;String name() default "";} }
使用示例
@ToString(exclude = {"dateOfBirth"}) public class ToStringDemo {String firstName;String lastName;LocalDate dateOfBirth; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class ToStringDemo {String firstName;String lastName;LocalDate dateOfBirth;public ToStringDemo() {}public String toString() {return "ToStringDemo(firstName=" + this.firstName + ", lastName=" +this.lastName + ")";} }
1.7 @Data
@Data 注解与同时使用以下的注解的效果是一样的:
- @ToString
- @Getter
- @Setter
- @RequiredArgsConstructor
- @EqualsAndHashCode
@Data 注解的定义如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface Data {String staticConstructor() default ""; }
使用示例
@Data public class DataDemo {private Long id;private String summary;private String description; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class DataDemo {private Long id;private String summary;private String description;public DataDemo() {}// 省略summary和description成员属性的setter和getter方法public Long getId() {return this.id;}public void setId(Long id) {this.id = id;}public boolean equals(Object o) {if (o == this) {return true;} else if (!(o instanceof DataDemo)) {return false;} else {DataDemo other = (DataDemo)o;if (!other.canEqual(this)) {return false;} else {// 已省略大量代码}}}protected boolean canEqual(Object other) {return other instanceof DataDemo;}public int hashCode() {int PRIME = true;int result = 1;Object $id = this.getId();int result = result * 59 + ($id == null ? 43 : $id.hashCode());Object $summary = this.getSummary();result = result * 59 + ($summary == null ? 43 : $summary.hashCode());Object $description = this.getDescription();result = result * 59 + ($description == null ? 43 : $description.hashCode());return result;}public String toString() {return "DataDemo(id=" + this.getId() + ", summary=" + this.getSummary() + ", description=" + this.getDescription() + ")";} }
1.8 @Log
若你将 @Log 的变体放在类上(适用于你所使用的日志记录系统的任何一种);之后,你将拥有一个静态的 final log 字段,然后你就可以使用该字段来输出日志。
1.9 @Synchronized
@Synchronized 是同步方法修饰符的更安全的变体。与 synchronized 一样,该注解只能应用在静态和实例方法上。它的操作类似于 synchronized 关键字,但是它锁定在不同的对象上。synchronized 关键字应用在实例方法时,锁定的是 this 对象,而应用在静态方法上锁定的是类对象。@Synchronized 注解的定义如下:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Synchronized {// 指定锁定的字段名称String value() default ""; }
使用示例:
public class SynchronizedDemo {private final Object readLock = new Object();@Synchronizedpublic static void hello() {System.out.println("world");}@Synchronizedpublic int answerToLife() {return 42;}@Synchronized("readLock")public void foo() {System.out.println("bar");} }
以上代码经过 Lombok 编译后,会生成如下代码:
public class SynchronizedDemo {private static final Object $LOCK = new Object[0];private final Object $lock = new Object[0];private final Object readLock = new Object();public SynchronizedDemo() {}public static void hello() {synchronized($LOCK) {System.out.println("world");}}public int answerToLife() {synchronized(this.$lock) {return 42;}}public void foo() {synchronized(this.readLock) {System.out.println("bar");}} }
1.10 @Builder
使用 @Builder 注解可以为指定类实现建造者模式,该注解可以放在类、构造函数或方法上。@Builder 注解的定义如下:
@Target({TYPE, METHOD, CONSTRUCTOR}) @Retention(SOURCE) public @interface Builder {@Target(FIELD)@Retention(SOURCE)public @interface Default {}// 创建新的builder实例的方法名称String builderMethodName() default "builder";// 创建Builder注解类对应实例的方法名称String buildMethodName() default "build";// builder类的名称String builderClassName() default "";boolean toBuilder() default false;AccessLevel access() default lombok.AccessLevel.PUBLIC;@Target({FIELD, PARAMETER})@Retention(SOURCE)public @interface ObtainVia {String field() default "";String method() default "";boolean isStatic() default false;} }
使用示例
@Builder public class BuilderDemo {private final String firstname;private final String lastname;private final String email; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class BuilderDemo {private final String firstname;private final String lastname;private final String email;BuilderDemo(String firstname, String lastname, String email) {this.firstname = firstname;this.lastname = lastname;this.email = email;}public static BuilderDemo.BuilderDemoBuilder builder() {return new BuilderDemo.BuilderDemoBuilder();}public static class BuilderDemoBuilder {private String firstname;private String lastname;private String email;BuilderDemoBuilder() {}public BuilderDemo.BuilderDemoBuilder firstname(String firstname) {this.firstname = firstname;return this;}public BuilderDemo.BuilderDemoBuilder lastname(String lastname) {this.lastname = lastname;return this;}public BuilderDemo.BuilderDemoBuilder email(String email) {this.email = email;return this;}public BuilderDemo build() {return new BuilderDemo(this.firstname, this.lastname, this.email);}public String toString() {return "BuilderDemo.BuilderDemoBuilder(firstname=" + this.firstname + ", lastname=" + this.lastname + ", email=" + this.email + ")";}} }
1.11 @SneakyThrows
@SneakyThrows 注解用于自动抛出已检查的异常,而无需在方法中使用 throw 语句显式抛出。@SneakyThrows 注解的定义如下:
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @Retention(RetentionPolicy.SOURCE) public @interface SneakyThrows {// 设置你希望向上抛的异常类Class<? extends Throwable>[] value() default java.lang.Throwable.class; }
使用示例
public class SneakyThrowsDemo {@SneakyThrows@Overrideprotected Object clone() {return super.clone();} }
以上代码经过 Lombok 编译后,会生成如下代码:
public class SneakyThrowsDemo {public SneakyThrowsDemo() {}protected Object clone() {try {return super.clone();} catch (Throwable var2) {throw var2;}} }
1.12 @NonNull
你可以在方法或构造函数的参数上使用 @NonNull 注解,它将会为你自动生成非空校验语句。@NonNull 注解的定义如下:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE}) @Retention(RetentionPolicy.CLASS) @Documented public @interface NonNull { }
使用示例
public class NonNullDemo {@Getter@Setter@NonNullprivate String name; }
以上代码经过 Lombok 编译后,会生成如下代码:
public class NonNullDemo {@NonNullprivate String name;public NonNullDemo() {}@NonNullpublic String getName() {return this.name;}public void setName(@NonNull String name) {if (name == null) {throw new NullPointerException("name is marked non-null but is null");} else {this.name = name;}} }
1.13 @Clean
@Clean 注解用于自动管理资源,用在局部变量之前,在当前变量范围内即将执行完毕退出之前会自动清理资源,自动生成 try-finally 这样的代码来关闭流。
@Target(ElementType.LOCAL_VARIABLE) @Retention(RetentionPolicy.SOURCE) public @interface Cleanup {// 设置用于执行资源清理/回收的方法名称,对应方法不能包含任何参数,默认名称为close。String value() default "close"; }
使用示例:
public class CleanupDemo {public static void main(String[] args) throws IOException {@Cleanup InputStream in = new FileInputStream(args[0]);@Cleanup OutputStream out = new FileOutputStream(args[1]);byte[] b = new byte[10000];while (true) {int r = in.read(b);if (r == -1) break;out.write(b, 0, r);}} }
以上代码经过 Lombok 编译后,会生成如下代码:
public class CleanupDemo {public CleanupDemo() {}public static void main(String[] args) throws IOException {FileInputStream in = new FileInputStream(args[0]);try {FileOutputStream out = new FileOutputStream(args[1]);try {byte[] b = new byte[10000];while(true) {int r = in.read(b);if (r == -1) {return;}out.write(b, 0, r);}} finally {if (Collections.singletonList(out).get(0) != null) {out.close();}}} finally {if (Collections.singletonList(in).get(0) != null) {in.close();}}} }
1.14 @With
在类的字段上应用 @With 注解之后,将会自动生成一个 withFieldName(newValue) 的方法,该方法会基于 newValue 调用相应构造函数,创建一个当前类对应的实例。@With 注解的定义如下:
@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface With {AccessLevel value() default AccessLevel.PUBLIC;With.AnyAnnotation[] onMethod() default {};With.AnyAnnotation[] onParam() default {};@Deprecated@Retention(RetentionPolicy.SOURCE)@Target({})public @interface AnyAnnotation {} }
使用示例
public class WithDemo {@With(AccessLevel.PROTECTED)@NonNullprivate final String name;@Withprivate final int age;public WithDemo(String name, int age) {if (name == null) throw new NullPointerException();this.name = name;this.age = age;} }
以上代码经过 Lombok 编译后,会生成如下代码:
public class WithDemo {@NonNullprivate final String name;private final int age;public WithDemo(String name, int age) {if (name == null) {throw new NullPointerException();} else {this.name = name;this.age = age;}}protected WithDemo withName(@NonNull String name) {if (name == null) {throw new NullPointerException("name is marked non-null but is null");} else {return this.name == name ? this : new WithDemo(name, this.age);}}public WithDemo withAge(int age) {return this.age == age ? this : new WithDemo(this.name, age);} }
四、lombok工作原理
核心之处就是对于注解的解析上。JDK5引入了注解的同时,也提供了两种解析方式。
- 运行时解析
运行时能够解析的注解,必须将@Retention设置为RUNTIME,这样就可以通过反射拿到该注解。java.lang.reflect反射包中提供了一个接口AnnotatedElement,该接口定义了获取注解信息的几个方法,Class、Constructor、Field、Method、Package等都实现了该接口,对反射熟悉的朋友应该都会很熟悉这种解析方式。
- 编译时解析
编译时解析有两种机制,分别简单描述下:
1)Annotation Processing Tool
apt自JDK5产生,JDK7已标记为过期,不推荐使用,JDK8中已彻底删除,自JDK6开始,可以使用Pluggable Annotation Processing API来替换它,apt被替换主要有2点原因:
- api都在com.sun.mirror非标准包下
- 没有集成到javac中,需要额外运行
2)Pluggable Annotation Processing API
JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强,javac执行的过程如下:
lombok工作原理
Lombok本质上就是一个实现了“JSR 269 API”的程序。在使用javac的过程中,它产生作用的具体流程如下:
- javac对源代码进行分析,生成了一棵抽象语法树(AST)
- 运行过程中调用实现了“JSR 269 API”的Lombok程序
- 此时Lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
- javac使用修改后的抽象语法树(AST)生成字节码文件,即给class增加新的节点(代码块)
jsr269抽象语法树操作API编译期注解处理-简单demo
JDK1.6引入了JSR269规范,允许在编译期处理注解,读取、修改、添加抽象语法树中的内容。
lombok插件就是应用了这个
1.自定义注解
package com.xiao.annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 自定义Data注解** @author xiaoss* @since 1.0, 2022年05月09日 09:43:44*/ @Target({ElementType.TYPE}) //标识作用对象 @Retention(RetentionPolicy.SOURCE) /* 注解保留策略类: 1)RetentionPolicy.SOURCE表示该注解只在源码中保留,编译之后class文件就不存在了 2)RetentionPolicy.CLASS表示该注解只保留到编译后,运行时候会被遗弃(如:在运行时通过反射去获取这个注解是找不到的) 3)RetentionPolicy.RUNTIME 表示该注解一直保留到运行 */ public @interface CustomData { }
2.创建处理器
package com.xiao.annotation;import com.google.auto.service.AutoService; import com.sun.source.tree.Tree; import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.util.*;import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import java.util.Set;/*** 自定义注解处理类,继承AbstractProcessor,重写init和process方法** @author xiaoss* @since 1.0, 2022年05月09日 10:05:59*/ @AutoService(Processor.class) @SupportedAnnotationTypes("com.xiao.annotation.CustomData") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class CustomDataAnnotationProcessor extends AbstractProcessor {private JavacTrees javacTrees;private TreeMaker treeMaker;private Names names;private Messager messager;/*** 从Context中初始化JavacTrees,TreeMaker,Names* @param processingEnv*/@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {messager.printMessage(Diagnostic.Kind.ERROR,"========================>init");super.init(processingEnv);Context context = ((JavacProcessingEnvironment) processingEnv).getContext();javacTrees = JavacTrees.instance(processingEnv);treeMaker = TreeMaker.instance(context);names = Names.instance(context);}@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {messager.printMessage(Diagnostic.Kind.ERROR,"========================>process");messager.printMessage(Diagnostic.Kind.NOTE, "source version -- " + getSupportedSourceVersion());// 获取注解类的集合,之后依次去处理Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(CustomData.class);for (Element element : set) {// 获取当前类的抽象语法树JCTree tree = javacTrees.getTree(element);// 获取抽象语法树的所有节点// Visitor 抽象内部类,内部定义了访问各种语法节点的方法tree.accept(new TreeTranslator() {@Overridepublic void visitClassDef(JCTree.JCClassDecl jcClassDecl) {jcClassDecl.defs.stream()// 过滤,只处理变量类型.filter(it -> it.getKind().equals(Tree.Kind.VARIABLE))// 类型强转.map(it -> (JCTree.JCVariableDecl) it).forEach(it -> {System.out.println(it.toString());// 添加get方法jcClassDecl.defs = jcClassDecl.defs.prepend(genGetterMethod(it));// 添加set方法jcClassDecl.defs = jcClassDecl.defs.prepend(genSetterMethod(it));});super.visitClassDef(jcClassDecl);}});}return true;}/*** 生成get方法* @param jcVariableDecl* @return*/private JCTree.JCMethodDecl genGetterMethod(JCTree.JCVariableDecl jcVariableDecl) {// 生成return语句,return this.xxxJCTree.JCReturn returnStatement = treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")),jcVariableDecl.getName()));ListBuffer<JCTree.JCStatement> statements = new ListBuffer<JCTree.JCStatement>().append(returnStatement);// public 方法访问级别修饰JCTree.JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);// 方法名 getXXX ,根据字段名生成首字母大写的get方法Name getMethodName = createGetMethodName(jcVariableDecl.getName());// 返回值类型,get类型的返回值类型与字段类型一致JCTree.JCExpression returnMethodType = jcVariableDecl.vartype;// 生成方法体JCTree.JCBlock body = treeMaker.Block(0, statements.toList());// 泛型参数列表List<JCTree.JCTypeParameter> methodGenericParamList = List.nil();// 参数值列表List<JCTree.JCVariableDecl> parameterList = List.nil();// 异常抛出列表List<JCTree.JCExpression> throwCauseList = List.nil();// 生成方法定义树节点return treeMaker.MethodDef(// 方法访问级别修饰符modifiers,// get 方法名getMethodName,// 返回值类型returnMethodType,// 泛型参数列表methodGenericParamList,//参数值列表parameterList,// 异常抛出列表throwCauseList,// 方法默认体body,// 默认值null);}/*** 生成set方法* @param jcVariableDecl* @return*/private JCTree.JCMethodDecl genSetterMethod(JCTree.JCVariableDecl jcVariableDecl) {// this.xxx=xxxJCTree.JCExpressionStatement statement = treeMaker.Exec(treeMaker.Assign(treeMaker.Select(treeMaker.Ident(names.fromString("this")),jcVariableDecl.getName()),treeMaker.Ident(jcVariableDecl.getName())));ListBuffer<JCTree.JCStatement> statements = new ListBuffer<JCTree.JCStatement>().append(statement);// set方法参数JCTree.JCVariableDecl param = treeMaker.VarDef(// 访问修饰符treeMaker.Modifiers(Flags.PARAMETER, List.nil()),// 变量名jcVariableDecl.name,//变量类型jcVariableDecl.vartype,// 变量初始值null);// 方法访问修饰符 publicJCTree.JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);// 方法名(setXxx),根据字段名生成首选字母大写的set方法Name setMethodName = createSetMethodName(jcVariableDecl.getName());// 返回值类型voidJCTree.JCExpression returnMethodType = treeMaker.Type(new Type.JCVoidType());// 生成方法体JCTree.JCBlock body = treeMaker.Block(0, statements.toList());// 泛型参数列表List<JCTree.JCTypeParameter> methodGenericParamList = List.nil();// 参数值列表List<JCTree.JCVariableDecl> parameterList = List.of(param);// 异常抛出列表List<JCTree.JCExpression> throwCauseList = List.nil();// 生成方法定义语法树节点return treeMaker.MethodDef(// 方法级别访问修饰符modifiers,// set 方法名setMethodName,// 返回值类型returnMethodType,// 泛型参数列表methodGenericParamList,// 参数值列表parameterList,// 异常抛出列表throwCauseList,// 方法体body,// 默认值null);}/*** 生成get方法名称* @param variableName* @return*/private Name createGetMethodName(Name variableName) {String fieldName = variableName.toString();return names.fromString("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));}/*** 生成set方法名称* @param variableName* @return*/private Name createSetMethodName(Name variableName) {String fieldName = variableName.toString();System.out.println(fieldName.substring(1));return names.fromString("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));}}
3.pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.xiao</groupId><artifactId>custom-annotation</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><java.home>D:\java\jdk1.8\</java.home></properties><dependencies><dependency><groupId>com.google.auto.service</groupId><artifactId>auto-service</artifactId><version>1.0</version></dependency><dependency><groupId>jdk.tools</groupId><artifactId>jdk.tools</artifactId><version>1.8</version><scope>system</scope><systemPath>${java.home}/lib/tools.jar</systemPath></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration><executions><execution><id>default-compile</id><configuration><compilerArgument>-proc:none</compilerArgument><source>1.8</source><target>1.8</target></configuration></execution></executions></plugin></plugins></build></project>
五、lombok优缺点
优点:
- 能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,提高了一定的开发效率
- 让代码变得简洁,不用过多的去关注相应的方法
- 属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等
缺点:
- 不支持多种参数构造器的重载
- 虽然省去了手动创建getter/setter方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度