sneaky visit( 四 )


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 MyGetter { // 定义 Getter}再实现一个自定义的注解处理器 , 代码如下:
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;@SupportedSourceVersion(SourceVersion.RELEASE_8)@SupportedAnnotationTypes("com.example.lombok.MyGetter")public class MyGetterProcessor extends AbstractProcessor {private Messager messager; // 编译时期输入日志的private JavacTrees javacTrees; // 提供了待处理的抽象语法树private TreeMaker treeMaker; // 封装了创建AST节点的一些方法private Names names; // 提供了创建标识符的方法@Overridepublic 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);}@Overridepublic boolean process(Set annotations, RoundEnvironment roundEnv) {Set elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(MyGetter.class);elementsAnnotatedWith.forEach(e -> {JCTree tree = javacTrees.getTree(e);tree.accept(new TreeTranslator() {@Overridepublic void visitClassDef(JCTree.JCClassDecl jcClassDecl) {List jcVariableDeclList = List.nil();// 在抽象树中找出所有的变量for (JCTree jcTree : jcClassDecl.defs) {if (jcTree.getKind().equals(Tree.Kind.VARIABLE)) {JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) jcTree;jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);}}// 对于变量进行生成方法的操作jcVariableDeclList.forEach(jcVariableDecl -> {messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed");jcClassDecl.defs = jcClassDecl.defs.prepend(makeGetterMethodDecl(jcVariableDecl));});super.visitClassDef(jcClassDecl);}});});return true;}private JCTree.JCMethodDecl makeGetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {ListBuffer statements = new ListBuffer<>();// 生成表达式 例如 this.a = a;JCTree.JCExpressionStatement aThis = makeAssignment(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName()), treeMaker.Ident(jcVariableDecl.getName()));statements.append(aThis);JCTree.JCBlock block = treeMaker.Block(0, statements.toList());// 生成入参JCTree.JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER),jcVariableDecl.getName(), jcVariableDecl.vartype, null);List parameters = List.of(param);// 生成返回对象JCTree.JCExpression methodType = treeMaker.Type(new Type.JCVoidType());return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),getNewMethodName(jcVariableDecl.getName()), methodType, List.nil(),parameters, List.nil(), block, null);}private Name getNewMethodName(Name name) {String s = name.toString();return names.fromString("get" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length()));}private JCTree.JCExpressionStatement makeAssignment(JCTree.JCExpression lhs, JCTree.JCExpression rhs) {return treeMaker.Exec(treeMaker.Assign(lhs,rhs));}}自定义的注解处理器是我们实现简易版的 Lombok 的重中之重 , 我们需要继承 AbstractProcessor 类 , 重写它的 init() 和 process() 方法 , 在 process() 方法中我们先查询所有的变量 , 在给变量添加对应的方法 。我们使用 TreeMaker 对象和 Names 来处理 AST , 如上代码所示 。


特别声明:本站内容均来自网友提供或互联网,仅供参考,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。