注释处理器是否可以访问上一轮生成的类型?
Is it possible for an annotation processor to access types generated in a previous round?
我有一个注释处理器,它为每个注释 class 生成一个 ID class。我希望 classes 能够引用同一编译单元中其他 classes 生成的 ID 类型。不幸的是,注释处理器似乎总是将生成的 class 类型给出为 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 class 确实存在于输出 jar 中) .这可以防止注释处理器分析 FooId
以找出它所属的包以便导入它。这个问题有解决办法吗?
Java 注释进程轮流执行其工作。在每一轮中,它将 运行 所有适用的注释处理器,然后编译输出。 Annotation Processor API 还会跟踪已处理的内容 类,并且只处理一次。您 运行 遇到的问题是您的 CreateIdProcessor
在 CheckIdProcessor
正在寻找它们的同一轮中生成 类。因为 FooId
没有在 CheckIdProcessor
运行 之前编译,调用 getEnclosedElements()
返回的 Element 是 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;
}
}
我有一个注释处理器,它为每个注释 class 生成一个 ID class。我希望 classes 能够引用同一编译单元中其他 classes 生成的 ID 类型。不幸的是,注释处理器似乎总是将生成的 class 类型给出为 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 class 确实存在于输出 jar 中) .这可以防止注释处理器分析 FooId
以找出它所属的包以便导入它。这个问题有解决办法吗?
Java 注释进程轮流执行其工作。在每一轮中,它将 运行 所有适用的注释处理器,然后编译输出。 Annotation Processor API 还会跟踪已处理的内容 类,并且只处理一次。您 运行 遇到的问题是您的 CreateIdProcessor
在 CheckIdProcessor
正在寻找它们的同一轮中生成 类。因为 FooId
没有在 CheckIdProcessor
运行 之前编译,调用 getEnclosedElements()
返回的 Element 是 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;
}
}