Java中的屠龙之术

Java中的屠龙之术

JCTree的介绍

CTree(Java Compiler Tree API)是 Java 编译器提供的一组 API,用于操作和分析 Java 代码的抽象语法树(AST)。JCTree API 在 com.sun.tools.javac.tree 包中提供,并且是 Java 编译器的一部分。它允许开发者在编译期间访问和修改 Java 代码的结构,从而实现代码生成、代码检查、代码转换等功能。

JCTree API 允许你以编程方式操作 AST 中的不同元素,如类、方法、字段、表达式等

以下是一些常见的 JCTree API 类和接口,以及它们的一些重要方法:

  1. JCCompilationUnit:表示整个编译单元(源文件)的抽象语法树。它是 AST 的根节点。
  2. JCClassDecl:表示类或接口的声明。
  3. JCMethodDecl:表示方法的声明。
  4. JCVariableDecl:表示变量(字段)的声明。
  5. JCExpression:表示表达式,如赋值、算术运算、方法调用等。
    • JCAssign:赋值语句语法树节点
    • JCIdent:标识符语法树节点,可以是变量,类型,关键字等等
  6. JCStatement:表示语句,如 if、while、for、return 等。
    • JCBlock:语句块语法树节点
    • JCReturn:return语句语法树节点
  7. JCTreeVisitor<R, D>:用于遍历和访问 AST 的访问者接口。你可以通过实现这个接口来定义如何处理不同类型的节点。

JavacTrees

com.sun.tools.javac.api.JavacTrees 是 Java 编译器(javac)提供的一个工具类,用于在注解处理器中访问和操作抽象语法树(AST)。它为注解处理器提供了一些便捷的方法,使得开发者可以更容易地在编译时处理 Java 源代码的结构。

JavacTrees 类主要用于获取与 AST 相关的一些工具和对象,包括:

  1. TreeMaker:用于创建新的 AST 节点,如创建类、方法、字段、表达式等。

  2. ElementTypeElement 的转换:可以将 Element 对象(表示程序元素)转换为对应的 TypeElementExecutableElement 等对象,以便进行更详细的操作。

  3. getTree(Element element):获取给定程序元素的对应 AST 节点。通过调用这个方法,你可以获取到表示该元素的 AST 节点。

  4. getScope(Element element):获取给定程序元素的对应作用域对象。这个作用域对象可以用于查询和分析元素的可见性等信息。

请注意,com.sun.tools.javac.api.JavacTrees 类属于 com.sun.tools.javac 包,这意味着它位于 javac 编译器的内部实现中。

以下是一个简单的示例,演示了如何在注解处理器中使用 JavacTrees 获取 AST 相关的信息:

TreeMaker

TreeMaker.Modifiers

TreeMaker.Modifiers方法用于创建访问标志语法树节点(JCModifiers)

public JCModifiers Modifiers(long flags) {
    return Modifiers(flags, List.< JCAnnotation >nil());
}

public JCModifiers Modifiers(long flags,
    List<JCAnnotation> annotations) {
        JCModifiers tree = new JCModifiers(flags, annotations);
        boolean noFlags = (flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0;
        tree.pos = (noFlags && annotations.isEmpty()) ? Position.NOPOS : pos;
        return tree;
}
  • flags:访问标志
  • annotations:注解列表
treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC + Flags.FINAL);

public static final
TreeMaker.ClassDef

TreeMaker.ClassDef用于创建类定义语法树节点(JCClassDecl)

public JCClassDecl ClassDef(JCModifiers mods,
    Name name,
    List<JCTypeParameter> typarams,
    JCExpression extending,
    List<JCExpression> implementing,
    List<JCTree> defs) {
        JCClassDecl tree = new JCClassDecl(mods,
                                     name,
                                     typarams,
                                     extending,
                                     implementing,
                                     defs,
                                     null);
        tree.pos = pos;
        return tree;
}
  • mods:访问标志,可以通过TreeMaker.Modifiers来创建
  • name:类名
  • typarams:泛型参数列表
  • extending:父类
  • implementing:实现的接口
  • defs:类定义的详细语句,包括字段、方法的定义等等
TreeMaker.MethodDef

TreeMaker.MethodDef用于创建方法定义语法树节点(JCMethodDecl)

public JCMethodDecl MethodDef(JCModifiers mods,
    Name name,
    JCExpression restype,
    List<JCTypeParameter> typarams,
    List<JCVariableDecl> params,
    List<JCExpression> thrown,
    JCBlock body,
    JCExpression defaultValue) {
        JCMethodDecl tree = new JCMethodDecl(mods,
                                       name,
                                       restype,
                                       typarams,
                                       params,
                                       thrown,
                                       body,
                                       defaultValue,
                                       null);
        tree.pos = pos;
        return tree;
}

public JCMethodDecl MethodDef(MethodSymbol m,
    Type mtype,
    JCBlock body) {
        return (JCMethodDecl)
            new JCMethodDecl(
                Modifiers(m.flags(), Annotations(m.getAnnotationMirrors())),
                m.name,
                Type(mtype.getReturnType()),
                TypeParams(mtype.getTypeArguments()),
                Params(mtype.getParameterTypes(), m),
                Types(mtype.getThrownTypes()),
                body,
                null,
                m).setPos(pos).setType(mtype);
}
  • mods:访问标志
  • name:方法名
  • restype:返回类型
  • typarams:泛型参数列表
  • params:参数列表
  • thrown:异常声明列表
  • body:方法体
  • defaultValue:默认方法(可能是interface中的哪个default)
  • m:方法符号
  • mtype:方法类型。包含多种类型,泛型参数类型、方法参数类型、异常参数类型、返回参数类型。
TreeMaker.VarDef

TreeMaker.VarDef用于创建字段/变量定义语法树节点

public JCVariableDecl VarDef(JCModifiers mods,
    Name name,
    JCExpression vartype,
    JCExpression init) {
        JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null);
        tree.pos = pos;
        return tree;
}

public JCVariableDecl VarDef(VarSymbol v,
    JCExpression init) {
        return (JCVariableDecl)
            new JCVariableDecl(
                Modifiers(v.flags(), Annotations(v.getAnnotationMirrors())),
                v.name,
                Type(v.type),
                init,
                v).setPos(pos).setType(v.type);
}
  • mods:访问标志
  • name:参数名称
  • vartype:类型
  • init:初始化语句
  • v:变量符号
TreeMaker.Ident

TreeMaker.Ident用于创建标识符语法树节点

public static class JCIdent extends JCTree.JCExpression implements IdentifierTree {
    public Name name;//标识符的名字
    public Symbol sym;//代表类时为包名+类名,代表其他类型数据时为null

    protected JCIdent(Name var1, Symbol var2) {
        this.name = var1;
        this.sym = var2;
    }
}

-->创建实例: 获取变量textView的引用
treeMaker.Ident(names.fromString("textView"))))
TreeMaker.Return

TreeMaker.Return用于创建return语句

public static class JCReturn extends JCTree.JCStatement implements ReturnTree {
    public JCTree.JCExpression expr;//返回语句的结果字段
}

-->例子:retrun this.xxx
treeMaker.Return(treeMaker.Select(
    treeMaker.Ident(names.fromString("this")),names.fromString("xxx")));
TreeMaker.Select

TreeMaker.Select用于创建域访问/方法访问

public JCFieldAccess Select(JCExpression selected,
    Name selector) 
{
        JCFieldAccess tree = new JCFieldAccess(selected, selector, null);
        tree.pos = pos;
        return tree;
}

public JCExpression Select(JCExpression base,
    Symbol sym) {
        return new JCFieldAccess(base, sym.name, sym).setPos(pos).setType(sym.type);
}
  • selected:.运算符左边的表达式
  • selector:.运算符右边的表达式
TreeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString("name"));

this.name
TreeMaker.Apply

TreeMaker.Apply用于创建方法调用语法树节点

public JCMethodInvocation Apply(List<JCExpression> typeargs,
    JCExpression fn,
    List<JCExpression> args) {
        JCMethodInvocation tree = new JCMethodInvocation(typeargs, fn, args);
        tree.pos = pos;
        return tree;
}
  • typeargs:参数类型列表
  • fn:调用语句
  • args:参数列表
TreeMaker.Assign

TreeMaker.Assign用户创建赋值语句语法树节点

ublic JCAssign Assign(JCExpression lhs,
    JCExpression rhs) {
        JCAssign tree = new JCAssign(lhs, rhs);
        tree.pos = pos;
        return tree;
}
  • lhs:赋值语句左边表达式
  • rhs:赋值语句右边表达式
TreeMaker.Exec

TreeMaker.Exec用于创建可执行语句语法树节点

public JCExpressionStatement Exec(JCExpression expr) {
        JCExpressionStatement tree = new JCExpressionStatement(expr);
        tree.pos = pos;
        return tree;
}

TreeMaker.Apply以及TreeMaker.Assign就需要外面包一层TreeMaker.Exec来获得一个JCExpressionStatement

TreeMaker.Block

TreeMaker.Block用于创建组合语句的语法树节点

public JCBlock Block(long flags,
    List<JCStatement> stats) {
        JCBlock tree = new JCBlock(flags, stats);
        tree.pos = pos;
        return tree;
}
  • flags:访问标志
  • stats:语句列表
public static class JCBlock extends JCTree.JCStatement implements BlockTree {
        public long flags;//访问修复符
        public List<JCTree.JCStatement> stats;//多行代码列表
}

-->使用例子:
List<JCTree.JCStatement> jcStatementList = List.nil();
treeMaker.Block(0, jcStatementList);//构建代码块
JCIf

if代码块; if(condition) {thenpart} else {elsepart}

public static class JCIf extends JCTree.JCStatement implements IfTree {
        public JCTree.JCExpression cond;//条件语句
        public JCTree.JCStatement thenpart;//if的操作语句
        public JCTree.JCStatement elsepart;//else的操作语句
}
JCForLoop

for循环代码块;for (init; cond; step) {body}

public static class JCForLoop extends JCTree.JCStatement implements ForLoopTree {
        public List<JCTree.JCStatement> init;
        public JCTree.JCExpression cond;
        public List<JCTree.JCExpressionStatement> step;
        public JCTree.JCStatement body;
}
JCTry、JCCatch
public static class JCTry extends JCTree.JCStatement implements TryTree {
        public JCTree.JCBlock body;//try代码块
        public List<JCTree.JCCatch> catchers;//JCCatch
        public JCTree.JCBlock finalizer;//final代码块
        public List<JCTree> resources;//List.nil(),用不上的字段
        public boolean finallyCanCompleteNormally;//
}

-->JCCatch
public static class JCCatch extends JCTree implements CatchTree {
        public JCTree.JCVariableDecl param;//catch的异常类型
        public JCTree.JCBlock body;//catch代码块
}

AbstractProcessor

AbstractProcessor 是 Java 注解处理器的一个抽象类,它是 Java 编译器提供的工具,用于处理源代码中的注解。注解处理器可以在编译时扫描和处理源代码中的注解信息,并根据注解生成代码、进行静态分析、执行代码检查等操作。

注解处理器是 Java 编译器的一部分,它可以用于生成额外的代码,修改现有的代码结构,或者在编译期间执行其他任务。这使得注解处理器非常适用于一些元编程和自动化的场景。

AbstractProcessor 作为注解处理器的抽象类,提供了一些常用的方法和操作,使得开发者可以更方便地编写自定义的注解处理器。它是 Java 标准库中的一部分,位于 javax.annotation.processing 包中。

以下是 AbstractProcessor 类的一些重要方法和用途:

  1. init 方法:在注解处理器被初始化时调用。开发者可以在这里进行初始化操作。

  2. getSupportedAnnotationTypes 方法:返回一个字符串集合,表示该处理器支持处理哪些注解。这些注解可以是完全限定名,也可以使用通配符。

  3. getSupportedSourceVersion 方法:返回一个表示支持的 Java 源代码版本的枚举值。通常返回 SourceVersion.latestSupported()

  4. process 方法:核心方法,用于处理注解。在这个方法中,你可以获取到编译器提供的注解信息和相关元素,然后执行处理逻辑。

ProcessingEnvironment

javax.annotation.processing.ProcessingEnvironment 是 Java 注解处理器的一个核心接口,它提供了注解处理器在编译时与编译环境进行交互的能力。通过 ProcessingEnvironment,注解处理器可以访问编译器提供的各种工具和信息,从而实现自定义的代码生成、静态分析、代码检查等功能。

ProcessingEnvironment 接口定义了许多有用的方法,使得注解处理器能够获取有关编译环境的各种信息。以下是一些 ProcessingEnvironment 接口中常用的方法:

  1. Messager getMessager():获取用于输出消息的 Messager 对象,允许注解处理器在编译时输出信息、警告和错误。

  2. Filer getFiler():获取用于生成文件的 Filer 对象,允许注解处理器生成新的源代码文件、类文件等。

  3. Elements getElementUtils():获取用于访问程序元素的 Elements 对象,允许注解处理器访问和操作源代码中的各种元素。

  4. Types getTypeUtils():获取用于处理类型信息的 Types 对象,允许注解处理器执行类型检查、类型转换等操作。

  5. Map<String, String> getOptions():获取注解处理器的选项集合,允许注解处理器获取外部传递的参数和选项。

  6. Locale getLocale():获取当前环境的语言设置,可以用于在不同语言环境下生成本地化的消息。

RoundEnvironment

在 Java 注解处理器中,RoundEnvironment 是一个用于表示当前编译轮次的对象,它提供了有关编译期间的注解信息和元素的访问接口。注解处理器在每个编译轮次都会被调用一次,并且每轮的 RoundEnvironment 对象都会提供当前轮次中的注解和元素信息。

每一轮的 RoundEnvironment 对象会包含一组元素,这些元素是被处理器所关注的注解所标注的程序元素(例如类、方法、字段等)。通过 RoundEnvironment,注解处理器可以获取到在当前轮次中被标注的元素,并进行相应的处理。

下面是一些常见的 RoundEnvironment 方法和用途:

  1. getElementsAnnotatedWith(Class<? extends Annotation> a):返回一个被给定注解标注的元素集合。通过传递注解的类对象,可以获取到被标注的类、方法、字段等元素。

  2. getElementsAnnotatedWith(TypeElement a):与上述方法类似,但是接受一个 TypeElement 参数。

  3. getElementsAnnotatedWith(javax.lang.model.element.ElementKind kind):返回指定元素类型的元素集合,例如 ElementKind.CLASSElementKind.METHOD 等。

  4. getRootElements():返回当前轮次中所有被处理的根元素,通常是源文件中的类。

ElementKind

javax.lang.model.element.ElementKind 是 Java 注解处理器中的一个枚举类型,用于表示程序元素(element)的种类或类型。程序元素是源代码中的各种构造,如类、接口、方法、字段等。ElementKind 枚举为每种元素提供了一个常量,帮助注解处理器在处理过程中判断和识别不同类型的元素。

以下是 ElementKind 中的一些常见元素种类和对应的常量:

  1. PACKAGE:表示包(package)元素。

  2. ENUM:表示枚举类型(enum)元素。

  3. CLASS:表示类(class)元素。

  4. INTERFACE:表示接口(interface)元素。

  5. ANNOTATION_TYPE:表示注解类型(annotation type)元素。

  6. ENUM_CONSTANT:表示枚举常量(enum constant)元素。

  7. FIELD:表示字段(field)元素。

  8. PARAMETER:表示方法或构造函数的参数(parameter)元素。

  9. LOCAL_VARIABLE:表示局部变量(local variable)元素。

  10. EXCEPTION_PARAMETER:表示异常参数(exception parameter)元素。

  11. METHOD:表示方法(method)元素。

  12. CONSTRUCTOR:表示构造函数(constructor)元素。

  13. STATIC_INIT:表示静态初始化块(static initializer)元素。

  14. INSTANCE_INIT:表示实例初始化块(instance initializer)元素。

  15. OTHER:表示其他未知类型的元素。

通过使用 ElementKind,注解处理器可以在处理不同类型的元素时执行不同的逻辑。例如,你可以根据元素的种类来判断是否生成额外的代码,或者是否进行特定类型的静态分析。

以下是一个简单的示例,演示如何使用 ElementKind 判断不同类型的元素:

import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.lang.model.SourceVersion;
import java.util.Set;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class ElementKindExample extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getRootElements()) {
            ElementKind kind = element.getKind();
            System.out.println("Element: " + element.getSimpleName() + ", Kind: " + kind);

            if (kind == ElementKind.CLASS) {
                System.out.println("Found class: " + element.getSimpleName());
            } else if (kind == ElementKind.METHOD) {
                System.out.println("Found method: " + element.getSimpleName());
            } else if (kind == ElementKind.FIELD) {
                System.out.println("Found field: " + element.getSimpleName());
            }
        }
        return true;
    }
}

在上述示例中,ElementKindExample 注解处理器遍历所有根元素,并根据元素的种类输出相应的信息。这有助于你了解不同类型的元素在注解处理器中的表现和处理方式。

通过熟悉和使用 ElementKind,你可以更好地理解和操作程序元素,从而在注解处理器中实现各种功能。

ExecutableElement

javax.lang.model.element.ExecutableElement 是 Java 注解处理器中的一个接口,它表示可执行元素,即方法和构造函数。ExecutableElement 继承自 Element 接口,提供了访问和操作方法和构造函数的属性和信息的方法。

在注解处理器中,你可以使用 ExecutableElement 来获取方法和构造函数的相关信息,例如方法名、参数、返回类型、注解等。

以下是 ExecutableElement 接口中的一些常用方法:

  1. List<? extends VariableElement> getParameters():获取方法或构造函数的参数列表。

  2. TypeMirror getReturnType():获取方法的返回类型。

  3. List<? extends TypeMirror> getThrownTypes():获取方法可能抛出的异常类型列表。

  4. TypeElement getEnclosingElement():获取包含该方法或构造函数的元素,通常是类或接口。

  5. boolean isVarArgs():检查方法是否为可变参数方法。

  6. boolean isDefault():检查方法是否为接口的默认方法。

  7. List<? extends TypeParameterElement> getTypeParameters():获取方法或构造函数的类型参数列表。

  8. List<? extends TypeMirror> getThrownTypes():获取方法可能抛出的异常类型列表。

  9. ExecutableType asType():将此 ExecutableElement 转换为 ExecutableType,用于进行类型检查。

TypeElement

javax.lang.model.element.TypeElement 是 Java 注解处理器中的一个接口,它表示程序元素中的类或接口。TypeElement 继承自 Element 接口,提供了访问和操作类和接口的属性和信息的方法。

在注解处理器中,你可以使用 TypeElement 来获取类和接口的相关信息,例如类名、父类、实现的接口、内部类、注解等。

以下是 TypeElement 接口中的一些常用方法:

  1. Name getQualifiedName():获取类或接口的限定名,以 Name 对象表示。

  2. TypeMirror getSuperclass():获取类的父类的类型。

  3. List<? extends TypeMirror> getInterfaces():获取类或接口实现的接口的类型列表。

  4. List<? extends Element> getEnclosedElements():获取类或接口中的成员元素,如字段、方法、内部类等。

  5. TypeMirror asType():将此 TypeElement 转换为 DeclaredType,用于进行类型检查。

  6. boolean isInterface():检查是否为接口。

  7. boolean isEnum():检查是否为枚举类型。

  8. boolean isAnnotation():检查是否为注解类型。

  9. boolean isClass():检查是否为类类型。

Messager

javax.annotation.processing.Messager 是 Java 注解处理器中的一个接口,它提供了向注解处理器的使用者(通常是开发者)报告消息、警告和错误的能力。通过 Messager,注解处理器可以向编译器输出信息,帮助开发者了解代码处理过程中的情况,以及可能需要修复的问题。

Messager 接口定义了一些方法,允许注解处理器输出消息、警告和错误。以下是 Messager 接口中常用的方法:

  1. void printMessage(Diagnostic.Kind kind, CharSequence msg):输出一条消息,可以是信息、警告或错误。

  2. void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e):输出一条消息,并指定与该消息关联的元素。

  3. void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a):输出一条消息,并指定与该消息关联的元素和注解镜像。

  4. void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v):输出一条消息,并指定与该消息关联的元素、注解镜像和注解值。

  5. void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v, AnnotationValue v1):输出一条消息,并指定与该消息关联的元素、注解镜像、注解值等。

  6. void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v, AnnotationValue v1, AnnotationValue v2):输出一条消息,并指定与该消息关联的元素、注解镜像、注解值等。

在编写注解处理器时,通常会使用 Messager 输出信息、警告和错误,以便在编译时向开发者传达处理结果和可能的问题。下面是一个简单的示例,展示了如何在注解处理器中使用 Messager 输出消息和警告:

作用到类上捕获异常
package com.jct.demo.processor;

/**
 * <b><code>CatchAndLogProcessor</code></b>
 * <p/>
 * Description
 * <p/>
 * <b>Creation Time:</b> 2023/8/14.
 *
 * @author zhennan.Xu
 * @since terry-boot
 */

import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.model.JavacElements;
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.Names;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

@SupportedAnnotationTypes("com.jct.demo.processor.CatchAndLog")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class CatchAndLogProcessor extends AbstractProcessor {
    private Trees trees;
    protected Messager messager;
    // 封装了创建AST节点的一些方法
    protected TreeMaker treeMaker;
    // 提供了创建标识符的方法
    protected Names names;
    /**
     * 用来处理Element的工具类
     * Elements接口的对象,用于操作元素的工具类。
     */
    private JavacElements elementUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        trees = Trees.instance(processingEnv);
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
        messager = processingEnv.getMessager();
        elementUtils = (JavacElements) processingEnv.getElementUtils();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("进入process");
        messager.printMessage(Diagnostic.Kind.NOTE, "TakeTimeProcessor注解处理器处理中");
        TypeElement currentAnnotation = null;
        //  遍历注解集合,也即@SupportedAnnotationTypes中标注的类型
        for (TypeElement annotation : annotations) {
            messager.printMessage(Diagnostic.Kind.NOTE, "遍历本注解处理器处理的所有注解,当前遍历到的注解是:" + annotation.getSimpleName());
            currentAnnotation = annotation;
        }
        Set<? extends Element> elementSet = roundEnv.getElementsAnnotatedWith(CatchAndLog.class);
        messager.printMessage(Diagnostic.Kind.NOTE, "CatchAndLogProcessor注解处理器处理@CatchAndLog注解");
        for (Element element : elementSet) {
            if (element.getKind() == ElementKind.METHOD) {
                JCTree tree = (JCTree) trees.getTree(element);
                System.out.println("进入循环");
                if (tree instanceof JCTree.JCMethodDecl) {
                    JCTree.JCMethodDecl methodDecl = (JCTree.JCMethodDecl) tree;
                    // 方法名称
                    String methodName = element.getSimpleName().toString();
                    // 类的全限定名称
                    String className = element.getEnclosingElement().toString();
                    messager.printMessage(Diagnostic.Kind.NOTE, "当前被标注注解的方法所在的类是:" + className);
                    messager.printMessage(Diagnostic.Kind.NOTE, currentAnnotation.getSimpleName().toString() + "当前被标注注解的方法是:" + methodName);
                    enhanceMethodDecl(methodDecl);
                }
            }
        }
        return true;
    }

    private void enhanceMethodDecl(JCTree.JCMethodDecl methodDecl) {
        //try {
        //
        //}catch (Exception ex) {
        //    ex.printStackTrace();
        //}
        JCTree.JCBlock tryBlock = methodDecl.body;
        JCTree.JCVariableDecl exVar = createVarDef(treeMaker.Modifiers(0),
            "ex",
            treeMaker.Ident(names.fromString("Exception")),
            null);

        JCTree.JCBlock catchBlock = treeMaker.Block(0L, List.of(
            treeMaker.Exec(treeMaker.Apply(
                List.nil(),
                treeMaker.Select(treeMaker.Ident(names.fromString("ex")),
                    names.fromString("printStackTrace")),
                List.nil()
            ))
        ));
        JCTree.JCCatch catchClause = treeMaker.Catch(exVar, catchBlock);
        JCTree.JCTry tryCatchTree = treeMaker.Try(tryBlock, List.of(catchClause), null);
        methodDecl.body = treeMaker.Block(0L, List.of(tryCatchTree));
        System.out.println(methodDecl.body.toString());
    }

    private com.sun.tools.javac.util.Name getNameFromString(String s) {
        return names.fromString(s);
    }

    /**
     * 创建变量语句
     *
     * @param modifiers
     * @param name      变量名
     * @param varType   变量类型
     * @param init      变量初始化语句
     * @return
     */
    private JCTree.JCVariableDecl createVarDef(JCTree.JCModifiers modifiers, String name, JCTree.JCExpression varType, JCTree.JCExpression init) {
        return treeMaker.VarDef(
            modifiers,
            //名字
            getNameFromString(name),
            //类型
            varType,
            //初始化语句
            init
        );
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐观的Terry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值