java AbstractProcessor无法使用JCTree修改现有方法

j7dteeu8  于 2023-06-20  发布在  Java
关注(0)|答案(1)|浏览(144)

AbstractProcessor可用于设计类似lombok所做的功能。在我的代码中,我有如下注解:

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface OnTransform {
}

然后我创建了一个类,并在我的方法上注解了这个注解,如下所示:

public class TargetClass {

@OnTransform
public int add(int a, int b) {
    return a + b;
}

@OnTransform
public void say(String name) {
    System.out.println("Hello " + name);
}

}

现在我想为这些带注解的方法添加try finally块,所以我做了一个新的类扩展AbstractProcessor类,并完成了我的代码如下(实际上这部分代码主要来自ChatGPT):

public class TransformProcessor extends AbstractProcessor {

/**
 * 初始化
 * @param processingEnv environment to access facilities the tool framework
 * provides to the processor
 */
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
    super.init(processingEnv);
    Context context = ((JavacProcessingEnvironment) this.processingEnv).getContext();
    this.elementUtils = (JavacElements) this.processingEnv.getElementUtils();
    this.messager = this.processingEnv.getMessager();
    this.names = Names.instance(context);
    this.trees = JavacTrees.instance(this.processingEnv);
    this.treeMaker = TreeMaker.instance(context);
}

/**
 * 用于在编译器打印消息的组件
 */
private Messager messager;

/**
 * 用于创建标识符的对象
 */
private Names names;

/**
 * 语法树
 */
private JavacTrees trees;

/**
 * trees 和 elementUtils都可以获取 元素的JCTree对象
 */
private JavacElements elementUtils;

/**
 * 用来构造语法树节点
 */
private TreeMaker treeMaker;

/**
 * 字段的语法树节点的集合
 */
private List<JCTree.JCMethodDecl> methodDecls;

/**
 * 允许支持的源码版本
 * @return
 */
@Override
public SourceVersion getSupportedSourceVersion() {
    if (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0) {
        return SourceVersion.latest();
    } else {
        return SourceVersion.RELEASE_8;
    }
}

/**
 * 允许支持的注解类型
 * @return
 */
@Override
public Set<String> getSupportedAnnotationTypes() {
    return ImmutableSet.of(OnTransform.class.getCanonicalName());
}

/**
 * 代码增强处理
 * @param annotations the annotation types requested to be processed
 * @param roundEnv  environment for information about the current and prior round
 * @return
 */
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(OnTransform.class);
    set.forEach(element -> {
        JCTree jcTree = trees.getTree(element);
        jcTree.accept(new TreeTranslator() {
            @Override
            public void visitMethodDef(JCTree.JCMethodDecl method) {
                // 运行父类方法
                super.visitMethodDef(method);
                // 获取方法体
                JCTree.JCBlock body = method.body;
                // 创建try语句块
                JCTree.JCBlock tryBlock = createTryBlock(body);
                // 创建finally语句块
                JCTree.JCBlock finallyBlock = createFinallyBlock();
                // 创建try-catch-finally语句块
                JCTree.JCTry tryFinally = createTryCatchFinally(tryBlock, finallyBlock);
                // 替换原来的方法体
                method.body = treeMaker.Block(0, List.of(tryFinally));
            }
        });
    });
    return true;
}

//create try block
private JCTree.JCBlock createTryBlock(JCTree.JCBlock body) {
     return treeMaker.Block(0, body.getStatements());
 }

// create finally block
private JCTree.JCBlock createFinallyBlock() {
    return treeMaker.Block(0, List.nil());
}

// create try-finally block
private JCTree.JCTry createTryCatchFinally(JCTree.JCBlock tryBlock, JCTree.JCBlock finallyBlock) {
    JCTree.JCTry aTry = treeMaker.Try(tryBlock, List.nil(), finallyBlock);
    return aTry;
}
}

我可以让我的项目编译成功,但. class文件似乎修改失败如下:

public class TargetClass {
public TargetClass() {
}

public int add(int a, int b) {
    return a + b;
}

public void say(String name) {
    System.out.println("Hello " + name);
}
}

我不知道为什么,我调试了代码,发现方法. body被改变了,但不知道为什么它没有正确地刷新到. class文件中。下面的代码不像预期的那样工作:

method.body = treeMaker.Block(0, List.of(tryFinally));

也许我用错了?

jk9hmnmh

jk9hmnmh1#

需要帮助,谷歌了很多,但没有喜欢

相关问题