Java 编译过程中处理环境成员的一致性

Java 编译过程中处理环境成员的一致性,java,annotations,annotation-processing,Java,Annotations,Annotation Processing,JDK 6和7中的Java注释处理API(不是5中的apt工具API)定义了注释处理器的生命周期。一个是通过no args构造函数实例化的,init方法通过ProcessingEnvironment实例调用,然后通过process方法使用该处理器。如果适用,在所有后续处理循环中,仅制作并使用一个处理器实例 因为我的处理器类有点臃肿,所以我为它应该处理的单独注释创建了处理程序类。在这些类的方法中,我总是传递元素和类型实例,这些实例是我从ProcessingEnvironment获取的,用于它们的实

JDK 6和7中的Java注释处理API(不是5中的apt工具API)定义了注释处理器的生命周期。一个是通过no args构造函数实例化的,
init
方法通过
ProcessingEnvironment
实例调用,然后通过
process
方法使用该处理器。如果适用,在所有后续处理循环中,仅制作并使用一个处理器实例

因为我的处理器类有点臃肿,所以我为它应该处理的单独注释创建了处理程序类。在这些类的方法中,我总是传递
元素
类型
实例,这些实例是我从
ProcessingEnvironment
获取的,用于它们的实用方法。这使得我的方法签名相当长

我宁愿只在处理程序和处理器实例中保留对
元素
类型
实例的引用。我通过将它们从
ProcessingEnvironment
传递到
init
方法中来实现这一点。现在,我想知道这是否安全。
Processor
的JavaDoc清楚地表明,某些方法对于一个处理器只调用一次,但是这里没有提到
init
。我假设这是隐含的理解,但我不是100%确定


我还想知道
Messager
实例(也可以从
ProcessingEnvironment
获得)是否在所有处理回合中都保持不变。我不希望某一轮出现警告/错误,而希望其他人被忽略。我可以合理地确定,在不同的回合中使用相同的实例应该是安全的,但我只是希望有一些确定性。

我问了自己同样的问题,并决定始终使用当前回合的
ProcessingEnvironment
init
提供的实用程序。使用javac时似乎没有任何区别,但是还有其他注释处理工具可能会显示不同的行为。我已经体验过javac中的处理工具和eclipse使用的处理工具之间的一些差异,因此我非常小心地处理文档中不明确的内容。问题是,是否要测试所有现有的处理工具


此外,我认为,如果那些处理助手工具永远不会更改,那么它们将是处理器构造函数的参数。

值得一提的是,如果多次调用its,则(建议作为实现者可以使用的子类)抛出
非法状态异常

这并不意味着传递的
ProcessingEnvironment
不能在随后的getter调用中或在不同的轮中返回不同的值,尽管这不是常规的。无论如何,在
过程开始时检查它可能是值得的
方法:

private ProcessingEnvironment processingEnv;
private Elements elementUtils;
private Types typeUtils;

public Processor() {
}

@Override
public synchronized void init(final ProcessingEnvironment processingEnv) {
    this.processingEnv = processingEnv;
    elementUtils = processingEnv.getElementUtils();
    typeUtils = processingEnv.getTypeUtils();
}

private void checkEnvironmentChange() {
    checkSame(elementUtils, processingEnv.getElementUtils(), "elementUtils");
    checkSame(typeUtils, processingEnv.getTypeUtils(), "typeUtils");
}

private <T> void checkSame(final T object1, final T object2, final String name) {
    if (object1 != object2) {
        throw new IllegalStateException(name + " should not change");
    }
}

@Override
public boolean process(final Set<? extends TypeElement> annotations, 
        final RoundEnvironment roundEnv) {
    checkEnvironmentChange();
    ...
}
private ProcessingEnvironment processingEnv;
私人要素;
私有类型;
公共处理器(){
}
@凌驾
公共同步void init(最终ProcessingEnvironment ProcessingEnvironment processingEnv){
this.processingEnv=processingEnv;
elementUtils=processingEnv.getElementUtils();
typeUtils=processingEnv.getTypeUtils();
}
私有void checkEnvironmentChange(){
选中相同(elementUtils,processingEnv.getElementUtils(),“elementUtils”);
选中相同(typeUtils,processingEnv.getTypeUtils(),“typeUtils”);
}
私有void checkSame(最终T对象1、最终T对象2、最终字符串名称){
if(object1!=object2){
抛出新的非法状态异常(名称+“不应更改”);
}
}
@凌驾

公共布尔过程(最终的设置点…我想知道为什么它们不是通过构造函数传入的,而是必须通过一些init方法。可能是设计约束?无论如何,我在init期间初始化处理程序,并为它们提供保留的实用程序的引用。如果多次调用init会有点问题。。。我不能让人替换处理程序,因为它们在不同的循环中保持状态。也许我也可以让init更新处理程序的工具引用。感谢Eclipse警告,你让我深思熟虑。这很有趣。每个编译只有一个处理器,并且init在默认抽象实现中只能被调用一次。至少这样听好这个问题。也许检查是否像你建议的那样返回了不同的值不是一个坏主意。我已经有一段时间没有做过这个了,所以我不记得这是否真的是一个问题…我想这取决于保留的对象是否有合适的重写equals方法。