Maven依赖
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.0-rc7</version>
<scope>provided</scope>
</dependency>
自定义注解 GetSetAnnotation
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 注解在编译器生效
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface GetSetAnnotation {
}
注解处理器 GetSetAnnotationProcessor
package com.example;
import com.google.auto.service.AutoService;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
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.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;
/**
* 使用AST,生成对应的getter,setter方法
*/
// 限定注解类型
@SupportedAnnotationTypes("com.example.GetSetAnnotation")
// 限定java版本号
@SupportedSourceVersion(SourceVersion.RELEASE_8)
// 借用SPI机制
@AutoService(Processor.class)
public class GetSetAnnotationProcessor extends AbstractProcessor {
private JavacTrees trees;
private TreeMaker treeMaker;
private Names names;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
// 获取抽象语法树实例
trees = JavacTrees.instance(processingEnv);
Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
treeMaker = TreeMaker.instance(context);
names = Names.instance(context);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(GetSetAnnotation.class)) {
if (element.getKind() == ElementKind.CLASS) {
// 获取类声明对象
JCTree.JCClassDecl classDecl = (JCTree.JCClassDecl) trees.getTree(element);
// 循环遍历类中所有封闭元素,包括字段、方法等
for (Element enclosed : element.getEnclosedElements()) {
// 若是私有字段,则生成getter,setter代码
if (enclosed.getKind() == ElementKind.FIELD && enclosed.getModifiers().contains(Modifier.PRIVATE)) {
// 获取字段声明
JCTree.JCVariableDecl fieldDecl = (JCTree.JCVariableDecl) trees.getTree(enclosed);
// classDecl.defs 表示 类的所有声明,包括字段、方法、初始化块等
classDecl.defs = classDecl.defs.append(makeGetterMethod(fieldDecl));
classDecl.defs = classDecl.defs.append(makeSetterMethod(fieldDecl));
}
}
} else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Only classes can be annotated with @GenerateGetterSetter", element);
}
}
return true;
}
/**
* 创建getter方法语法树
* @param field
* @return
*/
private JCTree.JCMethodDecl makeGetterMethod(JCTree.JCVariableDecl field) {
Name fieldName = field.getName();
// 方法名
String getterName = "get" + capitalize(fieldName.toString());
// 返回类型
JCTree.JCExpression returnType = field.vartype;
// 方法体
JCTree.JCBlock body = treeMaker.Block(0, List.of(
treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")), fieldName))
));
return treeMaker.MethodDef(
treeMaker.Modifiers(Flags.PUBLIC),
names.fromString(getterName),
returnType,
List.nil(),
List.nil(),
List.nil(),
body,
null
);
}
private JCTree.JCMethodDecl makeSetterMethod(JCTree.JCVariableDecl field) {
Name fieldName = field.getName();
String setterName = "set" + capitalize(fieldName.toString());
JCTree.JCExpression paramType = field.vartype;
JCTree.JCVariableDecl param = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER),
fieldName,
paramType,
null
);
JCTree.JCBlock body = treeMaker.Block(0, List.of(
treeMaker.Exec(
treeMaker.Assign(
treeMaker.Select(treeMaker.Ident(names.fromString("this")), fieldName),
treeMaker.Ident(fieldName)
)
)
));
return treeMaker.MethodDef(
treeMaker.Modifiers(Flags.PUBLIC),
names.fromString(setterName),
treeMaker.TypeIdent(com.sun.tools.javac.code.TypeTag.VOID),
List.nil(),
List.of(param),
List.nil(),
body,
null
);
}
private String capitalize(String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}
编译测试
项目打包
mvn clean package
测试类
package com.example;
@GetSetAnnotation
public class People {
private String name;
private int age;
}
编译命令
javac -cp target/aptexample-1.0-SNAPSHOT.jar -processor com.example.GetSetAnnotationProcessor src/main/java/com/example/People.java
编译结果
package com.example;
public class People {
private String name;
private int age;
public People() {
}
public String getName() {
return this.name;
}
public void setName(String var1) {
this.name = var1;
}
public int getAge() {
return this.age;
}
public void setAge(int var1) {
this.age = var1;
}
}
使用IDEA REMOTE JVM DEBUG 功能debug调试
创建 REMOTE JVM DEBUG
复制远程连接启动命令-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=55411
代码编译命令
# suspend=y 表示启动时暂停,等待远程连接
javac -J-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=55411 -cp target/aptexample-1.0-SNAPSHOT.jar -processor com.example.GetSetAnnotationProcessor src/main/java/com/example/People.java