gpt4 book ai didi

java - 如何通过 AnnotationProcessor 访问 TypeUse 注解

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:59:42 26 4
gpt4 key购买 nike

问题:

  1. 是否可以通过注释处理器访问使用 @Target(ElementType.TYPE_USE) 注释注释的元素?
  2. 是否可以通过注解处理器访问注解类型边界?

非常感谢我错过的相关文档链接。

上下文:

注释:

@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.SOURCE)
public @interface TypeUseAnno {}

示例类:

public class SomeClass extends HashMap<@TypeUseAnno String, String> {}

处理器:

@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("base.annotations.TypeUseAnno")
public class Processor extends AbstractProcessor {

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Initialized.");
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Invoked.");
for (TypeElement annotation : annotations) {
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "" + roundEnv.getElementsAnnotatedWith(annotation));
}
return true;
}
}

在类路径上使用 Processor 编译上述 SomeClass 将显示 "Initialized" 消息,但 process(... ) 方法永远不会被调用。当注释出现在方法参数上时,使用 @Target(ElementType.PARAMETER) 向处理器添加另一个注释效果很好。如果方法参数用 @TypeUseAnno 注释,进程将再次忽略该元素。

最佳答案

TYPE_USE 注释有点棘手,因为编译器对待它们的方式与“旧用法”注释不同。

因此,正如您正确观察到的那样,它们不会传递给注释处理器,并且您的 process() 方法永远不会接收到它们。

那么如何在编译时使用它们呢?

在引入这些注释的 Java 8 中,还引入了附加到 Java 编译的新方法。您现在可以将监听器附加到编译任务,并触发您自己的源代码遍历。因此,您访问注释的任务分为两部分。

  1. Hook 到编译器。
  2. 实现您的分析器。

广告 1。在 Java 8 中有 2 个选项可以 Hook 编译器:

  1. 使用new compiler plugin API .
  2. 使用注解处理器。

我没有太多地使用选项#1,因为它需要明确指定为 javac 参数。所以我将描述选项 #1:

您必须将 TaskListener 附加到正确的编译阶段。有不同的阶段。以下是唯一一个,在此期间您可以访问表示完整源代码的语法树,包括方法体(请记住,TYPE_USE 注释甚至可以用于局部变量声明。

@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EndProcessor extends AbstractProcessor {

@Override
public synchronized void init(ProcessingEnvironment env) {
super.init(env);
Trees trees = Trees.instance(env);
JavacTask.instance(env).addTaskListener(new TaskListener() {

@Override
public void started(TaskEvent taskEvent) {
// Nothing to do on task started event.
}

@Override
public void finished(TaskEvent taskEvent) {
if(taskEvent.getKind() == ANALYZE) {
new MyTreeScanner(trees).scan(taskEvent.getCompilationUnit(), null);
}
}

});
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// We don't care about this method, as it will never be invoked for our annotation.
return false;
}
}

广告 2。现在 MyTreeScanner 可以扫描完整的源代码,并找到注释。无论您使用 Plugin 还是 AnnotationProcessor 方法,这都适用。这仍然很棘手。您必须实现 TreeScanner,或者通常扩展 TreePathScanner。这代表了一种访问者模式,您必须在其中正确分析您感兴趣的元素。

让我们举一个简单的例子,它可以以某种方式对局部变量声明使用react(给我 5 分钟):

class MyTreeScanner extends TreePathScanner<Void, Void> {
private final Trees trees;

public MyTreeScanner(Trees trees) {
this.trees = trees;
}

@Override
public Void visitVariable(VariableTree tree, Void aVoid) {
super.visitVariable(variableTree, aVoid);
// This method might be invoked in case of
// 1. method field definition
// 2. method parameter
// 3. local variable declaration
// Therefore you have to filter out somehow what you don't need.
if(tree.getKind() == Tree.Kind.VARIABLE) {
Element variable = trees.getElement(trees.getPath(getCurrentPath().getCompilationUnit(), tree));
MyUseAnnotation annotation = variable.getAnnotation(MyUseAnnotation.class);
// Here you have your annotation.
// You can process it now.
}
return aVoid;
}
}

这是非常简短的介绍。有关真实示例,您可以查看以下项目源代码: https://github.com/c0stra/fluent-api-end-check/tree/master/src/main/java/fluent/api/processors

在开发此类功能时进行良好的测试也非常重要,这样您就可以调试、逆向工程并解决您将在该领域面临的所有棘手问题;)为此,您还可以在这里获得灵感: https://github.com/c0stra/fluent-api-end-check/blob/master/src/test/java/fluent/api/EndProcessorTest.java

也许是我的最后一句话,由于 javac 使用的注释确实不同,因此存在一些限制。例如。它不适合触发 java 代码生成,因为编译器不会选择在此阶段创建的文件进行进一步编译。

关于java - 如何通过 AnnotationProcessor 访问 TypeUse 注解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55218187/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com