我有一个注释处理器,为每个带注释的类生成一个ID类。我希望类能够在同一个编译单元中引用其他类的生成的ID类型。不幸的是,似乎注释处理器总是将生成的类作为ERROR提供,即使该类型是在先前的编译轮次中生成的,也可能是由完全独立的处理器生成的。有办法解决这个问题吗?
这是一个极小的例子。说我有以下课程:
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
的类型视为ERROR,即使它是由第一个处理器生成的(并且FooId类确实存在于输出jar中)。这可以防止注释处理器分析FooId
,例如,找出它所属的包以便导入它。这个问题有没有解决方法?
答案 0 :(得分:4)
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;
}
}