我有一个注释处理器,它为每个注释类生成一个 ID 类。我希望类能够引用同一编译单元中其他类生成的 ID 类型。不幸的是,注释处理器似乎总是将生成的类的类型给出为 ERROR,即使该类型是在前一轮编译中生成的或由完全独立的处理器生成的。有解决办法吗?
这是一个最小的例子。假设我有以下类(class):
package tmp;
@MyAnnotation
public class Foo {
private Foo me;
private FooId myId;
}
它首先由这个注释处理器处理以生成 ID:
@SupportedAnnotationTypes("tmp.proc.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class CreateIdProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element elem : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
System.out.println("Writing ID for " + elem.getSimpleName());
try {
Writer file = processingEnv.getFiler().createSourceFile(elem + "Id").openWriter();
file.write(String.format("package tmp; public class %sId {}", elem.getSimpleName()));
file.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return false;
}
}
然后由这个注释处理器处理以分析类型:
@SupportedAnnotationTypes("tmp.proc.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class CheckIdProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element elem : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
for (Element element : elem.getEnclosedElements()) {
System.out.printf("%s = %s (%s)\n", element.getSimpleName(), element.asType(), element.asType().getKind());
}
}
return false;
}
}
运行构建的输出如下所示:
Writing ID for Foo
<init> = ()void (EXECUTABLE)
me = tmp.Foo (DECLARED)
myId = FooId (ERROR)
一切都编译正常,但第二个处理器将 myId
的类型视为错误,即使它是由第一个处理器生成的(并且 FooId 类确实存在于输出 jar 中)。这可以防止注释处理器分析 FooId
以找出它所属的包以便导入它。这个问题有什么解决方法吗?
最佳答案
Java Annotation Process 轮流执行其工作。在每一轮中,它将运行所有适用的注释处理器,然后编译输出。 Annotation Processor API 还跟踪哪些类已被处理,并且只处理一次。您遇到的问题是您的 CreateIdProcessor
在 CheckIdProcessor
正在寻找它们的同一轮中生成类。因为 FooId
在 CheckIdProcessor
运行之前没有被编译,调用 getEnclosedElements()
返回的元素是 ERROR
元素。
简而言之,您的第二个处理器将 FooId
字段类型视为错误,因为生成了 FooId
的源代码,但尚未编译。
这是您可以运行的实验。这个注释处理器将打印出在给定回合中处理的所有新类。 FooId
出现在 Round: 1
下,而 Foo
会出现在 Round: 0
下:
Round: 0
Foo = tmp.Foo (DECLARED)
<init> = ()void (EXECUTABLE)
me = tmp.Foo (DECLARED)
myId = FooId (ERROR)
Writing ID for Foo
Round: 1
FooId = tmp.FooId (DECLARED)
Round: 2
Round: 3
这是我为此使用的注释处理器:
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class OutputRoundProcessor extends AbstractProcessor {
private int round = 0;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
System.out.println("Round: " + round);
for (Element element : roundEnv.getRootElements()) {
System.out.printf("%s = %s (%s)\n", element.getSimpleName(), element.asType(), element.asType().getKind());
}
round++;
return false;
}
}
关于java - 注释处理器是否可以访问上一轮生成的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30113866/