Project-1 提供注解处理器
pom.xml ```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">
4.0.0 org.example processor-core 1.0-SNAPSHOT UTF-8 1.8 1.8 ${env.JAVA_HOME}/lib/tools.jar 
<dependencies><!-- 自动生成SPI文件 --><dependency><groupId>com.google.auto.service</groupId><artifactId>auto-service</artifactId><version>1.0-rc5</version></dependency><!-- AST工具包 --><dependency><groupId>com.sun</groupId><artifactId>tools</artifactId><version>1.8</version><scope>system</scope><systemPath>${tools.path}</systemPath><optional>true</optional></dependency></dependencies>
说明:AST 抽象语法树, JDK lib包中的tools.jar中提供了操作抽象语法树的API。2. 定义注解,要求@Retention(RetentionPolicy.SOURCE)```java@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)public @interface GetterSetter {}
- 定义注解处理器, 通过tools.jar中操作抽象语法树的API,给类增加get/set方法 ```java package org.example.core;
 
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.code.TypeTag; 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.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.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import java.util.HashSet; import java.util.Set;
/**
- 还可以通过-processor参数来执行编译时需要附带的注解处理器,多个逗号分隔。
 还可以使用-XprintRounds 和 -XprintProcessorInfo 参数来查看注解处理器运作的详细信息。 */ @AutoService(Processor.class) //简化了SPI的配置 @SupportedAnnotationTypes(“org.example.core.GetterSetter”) public class GetterSetterProcessor extends AbstractProcessor {
private Messager messager; // 消息
private JavacTrees javacTrees; // 抽象语法树工具
private TreeMaker treeMaker; // 操作节点工具 - 核心工具
private Names names; // 处理名称工具
@Override public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest(); // 指定可处理的java版本
}
@Override public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv); // 注解处理器框架提供的上下文环境// 额外初始化一些资源操作对象this.messager = processingEnv.getMessager();this.javacTrees = JavacTrees.instance(processingEnv);Context context = ((JavacProcessingEnvironment) processingEnv).getContext();this.treeMaker = TreeMaker.instance(context);this.names = Names.instance(context);
}
/**
- 核心处理逻辑 *
 - @param annotations 感兴趣的注解
 - @param roundEnv 当前轮次(Round)的抽象语法树节点,所有节点类型(ElementKind)
 @return 是否改动过节点 */ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// 当前处理器已处理过,不在进行处理 if (roundEnv.processingOver()) {
return true;
}
print(“开始处理”); print(“处理注解:” + annotations); messager.printMessage(Diagnostic.Kind.NOTE, “roundEnv ->” + roundEnv);
for (TypeElement annotation : annotations) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(annotation);for (Element element : elements) {print("处理注解:" + annotation + "开始处理元素:" + element);// 存放所有变量,也可以list,不过这里不太方便Set<JCTree.JCVariableDecl> paramSet = new HashSet<>();// 获取元素对象的抽象语法树JCTree jcTree = javacTrees.getTree(element);// 标准的访问者模式jcTree.accept(new TreeTranslator() {/*** 遍历每个变量*/@Overridepublic void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) {paramSet.add(jcVariableDecl); // 存起来super.visitVarDef(jcVariableDecl);}@Overridepublic void visitClassDef(JCTree.JCClassDecl jcClassDecl) {super.visitClassDef(jcClassDecl); // 会先走 visitVarDef// 转换List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();for (JCTree.JCVariableDecl jcVariableDecl : paramSet) {jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);}print("------------------------\n本次处理参数:");jcVariableDeclList.forEach((var) -> print(var));print("------------------------");// 获取所有getter/setter方法List<JCTree.JCMethodDecl> jcMethodDeclList = generateMethod(jcVariableDeclList);// 添加到类中for (JCTree.JCMethodDecl jcMethodDecl : jcMethodDeclList) {jcClassDecl.defs = jcClassDecl.defs.append(jcMethodDecl);}}});}
}
print(“处理结束”);
// 指示处理器改变过代码,需要修改语法树的内容 // 编译器会重新回到解析及填充符号表的过程 return true; }
private List
generateMethod(List jcVariableDeclList) { List
jcMethodDeclList = List.nil(); for (JCTree.JCVariableDecl jcVariableDecl : jcVariableDeclList) {
JCTree.JCMethodDecl getter = getGetter(jcVariableDecl);JCTree.JCMethodDecl setter = getSetter(jcVariableDecl);jcMethodDeclList = jcMethodDeclList.append(getter);jcMethodDeclList = jcMethodDeclList.append(setter);
}
return jcMethodDeclList; }
private JCTree.JCMethodDecl getGetter(JCTree.JCVariableDecl jcVariableDecl) { JCTree.JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC); //访问修饰符
Name methodName = names.fromString(“get” + upper(jcVariableDecl.name.toString())); // 方法名
List
jcReturns = List.of(treeMaker.Return( treeMaker.Select(// this -> nametreeMaker.Ident(names.fromString("this")), jcVariableDecl.name))
); // 代码块 JCTree.JCBlock block = treeMaker.Block(0, jcReturns); // 0 -> 没有任何修饰符
return treeMaker.MethodDef(
modifiers, // 访问修饰符methodName, // 方法名jcVariableDecl.vartype, // 返回类型List.nil(), // 泛型列表List.nil(), // 参数列表List.nil(), // 异常列表block, // 方法体null // 默认值,注解才有
); }
private JCTree.JCMethodDecl getSetter(JCTree.JCVariableDecl jcVariableDecl) { JCTree.JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC); //访问修饰符
JCTree.JCPrimitiveTypeTree rtnType = treeMaker.TypeIdent(TypeTag.VOID); // 方法返回类型
Name methodName = names.fromString(“set” + upper(jcVariableDecl.name.toString())); // 方法名
JCTree.JCVariableDecl param = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER), // 变量类型 - 参数jcVariableDecl.getName(), // 参数名jcVariableDecl.vartype, // 参数类型null // ...
); // 形参
param.pos = jcVariableDecl.pos; // 坑,1小时
List
jcAssigns = List.of(treeMaker.Exec( // =treeMaker.Assign(// this.xxx, xxxtreeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString(jcVariableDecl.name.toString())), treeMaker.Ident(param.name))
));// 代码块
JCTree.JCBlock block = treeMaker.Block(0, jcAssigns); // 0 -> 没有任何修饰符
return treeMaker.MethodDef(
modifiers, // 访问修饰符methodName, // 方法名rtnType, // 返回类型List.nil(), // 泛型列表List.of(param), // 参数列表List.nil(), // 异常列表block, // 方法体null // 默认值,注解才有
); }
private String upper(String str) { char[] cs = str.toCharArray(); cs[0] -= 32; return String.valueOf(cs); }
private void print(Object msg) { System.out.println(msg.toString()); } }
说明:@AutoService(Processor.class) 是简化SPI的配置,编译当前类(GetterSetterProcessor.java)的时候会自动生成SPI的配置信息。<br />在classpath下生成如下路径和文件:\META-INF\services\(目录) + 接口全限定名 <br />\META-INF\services\javax.annotation.processing.Processor<br />文件的内容为接口的实现类:org.example.core.GetterSetterProcessor<a name="PLfP2"></a># Project-2 使用编译时注解1. pom.xml中引入project-1的jar```xml<dependencies><dependency><groupId>org.example</groupId><artifactId>processor-core</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
- 使用注解 ```java package org.example.invoke;
 
import org.example.core.GetterSetter;
import java.util.List;
@GetterSetter public class User {
private int age;private String name;private List<String> stringList;
}
3. 编译后的User.java```javapackage org.example.invoke;import java.util.List;public class User {private int age;private String name;private List<String> stringList;public User() {}public String getName() {return this.name;}public void setName(String name) {this.name = name;}public List<String> getStringList() {return this.stringList;}public void setStringList(List<String> stringList) {this.stringList = stringList;}public int getAge() {return this.age;}public void setAge(int age) {this.age = age;}}
- 测试 ```java package org.example.invoke;
 
public class TestGetter {
public static void main(String[] args) {User user = new User();user.setName("zs");System.out.println(user.getName());}
}
```
https://gitee.com/java-base-devin/processor-core.git
https://gitee.com/java-base-devin/processor-invoke.git
