JDK6.0的新特性之六:插入式注解处理API(可插入注释处理API)

作者:飞翼发表日期:2007-01-03 20:10

插入式注解处理API (JSR 269)提供一套标准API来处理注释(JSR 175),实际上JSR 269不仅仅用来处理注释,我觉得更强大的功能是它建立了Java语言本身的一个模型,它把方法、方案,构造函数,类型、变量、枚举、注释等Java语言元素映射为类型和元素(两者有什么区别?),从而将Java语言的语义映射成为对象,我们可以在javax.lang.model包下面可以看到这些类。所以我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(元编程)环境。JSR 269用注解处理器在编译期间而不是运行期间处理注释,注释处理器相当于编译器的一个插件,所以称为插入式注解处理。如果注解处理器处理注释时(执行处理方法)产生了新的Java代码,编译器会再调用一次注解处理器,如果第二次处理还有新代码产生,就会接着调用注解处理器,直到没有新代码产生为止。每执行一次过程()方法被称为一个“圆”,这样整个注解处理过程可以看作是一个圆形的序列。JSR 269主要被设计成为针对工具或者容器的API。举个例子,我们想建立一套基于注释的单元测试框架(如TestNG),在测试类里面用注释来标识测试期间需要执行的测试方法,如下所示:

@TestMethod
公共空间testCheckName () {
//做一些
}

这时我们就可以用JSR 269提供的API来处理测试类,根据注释提取出需要执行的测试方法。

另一个例子是如果我们出于某种原因需要自行开发一个符合Java EE 5.0的应用程序服务器(当然不建议这样做),我们就必须处理常见的注释(JSR 250), Web服务元数据(JSR 181)等规范的注释,这时可以用JSR 269提供的API来处理这些注释。在现在的开发工具里面,Eclipse 3.3承诺将支持JSR 269

下面我用代码演示如何来用JSR 269提供的API来处理注释和读取Java源文件的元数据(元数据)

/* *
*由IntelliJ IDEA。
*用户:Chinajash
*日期:2006年12月31日,
*/
@SupportedAnnotationTypes (PluggableAPT.ToBeTested)//可以用“*”表示支持所有Annotations@SupportedSourceVersion (SourceVersion.RELEASE_6)
公共类MyAnnotationProcessor延伸AbstractProcessor {
私人空间注意(字符串味精){
processingEnv.getMessager () .printMessage (Diagnostic.Kind。注意,味精);
}
公共逻辑过程(<?扩展TypeElement>注释,RoundEnvironment roundEnv) {
//注释的值是通过@SupportedAnnotationTypes声明的且目标源代码拥有的所有注释
(TypeElement te:注释){
注意(注释:“+ te.toString ());
}
<?扩展元素>元素=roundEnv.getRootElements();//获取源代码的映射对象的(元素e:元素){
//获取源代码对象的成员列表<?扩展元素> enclosedElems=e.getEnclosedElements ();
//留下方法成员,过滤掉其他成员列表
<?扩展ExecutableElement> ee=ElementFilter.methodsIn (enclosedElems);
(ExecutableElement ee: ee) {
注意(”——ExecutableElement叫“+ ee.getSimpleName());列表
<?扩展AnnotationMirror>=ee.getAnnotationMirrors();//获取方法的注释
注意(“——=" +);
(AnnotationMirror问:作为){
//获取注释的值
<地图吗?ExecutableElement延伸,?扩展AnnotationValue>地图=am.getElementValues ();
<?扩展ExecutableElement> ks=map.keySet ();
(ExecutableElement k: ks){//打印注释的每个值AnnotationValue av=map.get (k),
注意(“——”+ ee.getSimpleName () +“。”+ k.getSimpleName () + "=" + av.getValue ());
}
}
}
}
返回false;
}
}

@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.METHOD)
@ interface ToBeTested {
字符串所有者()默认“Chinajash”;
字符串组();
}

编译以上代码,然后再创建下面的测试对象,不要编译测试对象,我在后面会编译它

公共类测试{
@ToBeTested(集团=癆”)
公共空m1 () {
}
@ToBeTested(组=癇”,所有者=癚Q”)
公共空m2 () {
}
@PostConstruct//常见的注释里面的一个注释
公共空m3 () {
}
}

下面我用以下命令编译测试对象

javac -XprintRounds处理器PluggableAPT。MyAnnotationProcessor测试。java

-XprintRounds表示打印轮的次数,运行上面命令后在控制台会看到如下输出:

轮1:
输入文件:{PluggableAPT。测试}
注释:[PluggableAPT。ToBeTested javax.annotation。PostConstruct]
最后一轮:假
注意:注释:PluggableAPT。ToBeTested
注意:——ExecutableElement叫m1
注意:——=@PluggableAPT.ToBeTested(集团=癆”)
注意:- - - - - m1。组=
注意:——ExecutableElement叫m2
注意:——=@PluggableAPT。ToBeTested(组=癇”,所有者=癚Q”)

JDK6.0的新特性之六:插入式注解处理API(可插入注释处理API)