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