注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

FlyingWind

 
 
 

日志

 
 
 
 

JDK6的新特性(六)插入式注解处理API   

2008-08-10 14:43:16|  分类: JAVA资料 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
?kjf*
C Q$e. ] JDK6的新特性之六:插入式注解处理API(Pluggable Annotation Processing API)  
0?LlKO^Qw  
-=~s93FlO 插 入式注解处理API(JSR 269)提供一套标准API来处理Annotations(JSR 175),实际上JSR 269不仅仅用来处理Annotation,我觉得更强大的功能是它建立了Java 语言本身的一个模型,它把method, package, constructor, type, variable, enum, annotation等Java语言元素映射为Types和Elements(两者有什么区别?), 从而将Java语言的语义映射成为对象, 我们可以在javax.lang.model包下面可以看到这些类. 所以我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(metaprogramming)环境. JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation, Annotation Processor相当于编译器的一个插件,所以称为插入式注解处理.如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止.每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列. JSR 269主要被设计成为针对Tools或者容器的API. 举个例子,我们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试 方法,如下所示: 
UuVb~&\X  
`VkuL-#p @TestMethod 
D})[UI{ public void testCheckName(){ 
~#T.kwU     //do something here 
9u8q.
>["t"[  
6 9ur (+?c 这时我们就可以用JSR 269提供的API来处理测试类,根据Annotation提取出需要执行的测试方法.  
P00WoB  
u-TL^eY'ky 另 一个例子是如果我们出于某种原因需要自行开发一个符合Java EE 5.0的Application Server(当然不建议这样做),我们就必须处理Common Annotations(JSR 250),Web Services Metadata(JSR 181)等规范的Annotations,这时可以用JSR 269提供的API来处理这些Annotations. 在现在的开发工具里面,Eclipse 3.3承诺将支持JSR 269 
s}]#dBzS  
E_XLb*\ 下面我用代码演示如何来用JSR 269提供的API来处理Annotations和读取Java源文件的元数据(metadata) 
)^S)d>X  
 a:$A /** 
u|Fs~?Zl * Created by IntelliJ IDEA. 
?9Bnb% * User: Chinajash 
^?56X@MdP * Date: Dec 31, 2006 
p(aojAlbU */ 
*7Um~O @SupportedAnnotationTypes("PluggableAPT.ToBeTested")//可以用"*"表示支持所有Annotations 
C:#,GjPT @SupportedSourceVersion(SourceVersion.RELEASE_6) 
WO)Tk p^ public class MyAnnotationProcessor extends AbstractProcessor { 
_I8&")1_f   private void note(String msg) { 
Wq <]nS "     processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg); 
40{-t7+iN   } 
H3J&e_<C+   public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
D_TLx[f'     //annotations的值是通过@SupportedAnnotationTypes声明的且目标源代码拥有的所有Annotations 
vs^@P6"D?}     for(TypeElement te:annotations){ 
Z3S5?[N         note("annotation:"+te.toString()); 
z `^]bL$     } 
'j5:JD     Set<? extends Element> elements = roundEnv.getRootElements();//获取源代码的映射对象 
A~3}q_K(     for(Element e:elements){ 
U`:A5bxiz         //获取源代码对象的成员 
kSs&' 1{Q         List<? extends Element> enclosedElems = e.getEnclosedElements(); 
>0I lcyH         //留下方法成员,过滤掉其他成员 
)sr]14ion         List<? extends ExecutableElement> ees = ElementFilter.methodsIn(enclosedElems); 
uwR%Z+         for(ExecutableElement ee:ees){ 
EG=?J ,           note("--ExecutableElement name is "+ee.getSimpleName()); 
vS1;{< }mX           List<? extends AnnotationMirror> as = ee.getAnnotationMirrors();//获取方法的Annotations 
0/Ge>Q& kJ           note("--as="+as);  
LOE#1LO           for(AnnotationMirror am:as){ 
w8MEV9jQd             //获取Annotation的值 
-S\^!3lTU4             Map<? extends ExecutableElement, ? extends AnnotationValue> map= am.getElementValues(); 
L yI&@2,             Set<? extends ExecutableElement> ks = map.keySet(); 
pI*t=3$             for(ExecutableElement k:ks){//打印Annotation的每个值 
Ui.QZhK                 AnnotationValue av = map.get(k); 
yRyoN$                 note("----"+ee.getSimpleName()+"."+k.getSimpleName()+"="+av.getValue()); 
k0 !1?*             } 
#VjsqWF}k9           } 
2 q@Gm 7         } 
fa nS3YR     } 
uS=FJ >     return false; 
d5I|%)qm?W   } 
HX*au)m K
io.7W8#p  
Bz|ak[(/ @Retention(RetentionPolicy.RUNTIME) 
RW#UY^ @Target(ElementType.METHOD) 
MeZ (Jb @interface ToBeTested{ 
Y!:c(x4-S   String owner() default "Chinajash"; 
Sv}1\6U(VK   String group(); 
%SvcYNZ
<lc54/k}  
R;/Bi,< 编译以上代码,然后再创建下面的Testing对象,不要编译Testing对象,我在后面会编译它 
JIlz;m 8(%  
\!0H,cEl public class Testing{    
\[ci4,:8   @ToBeTested(group="A") 
</t7 " Q@U   public void m1(){ 
v NlS~Z   } 
Ze =mTWLs   @ToBeTested(group="B",owner="QQ") 
#kAG~WAs   public void m2(){ 
6g:$tE3HOe   }    
uW mvC )   @PostConstruct//Common Annotation里面的一个Annotation 
{^Nl4=l   public void m3(){ 
yQgP ]ulK   }    
I7g?MFf.
~hr^%N Pi  
j?Od[CX 下面我用以下命令编译Testing对象 
_:-bub"Z  
~XG''GUDbU javac -XprintRounds -processor PluggableAPT.MyAnnotationProcessor Testing.java 
<)Y?\`  
Z;4UO7r -XprintRounds表示打印round的次数,运行上面命令后在控制台会看到如下输出: 
l B{->  
u a{g Round 1: 
|i;Rr>i{z%     input files: {PluggableAPT.Testing} 
jv+'Eo C''     annotations: [PluggableAPT.ToBeTested, javax.annotation.PostConstruct] 
b IKky\     last round: false 
r*a ]0X=e Note: annotation:PluggableAPT.ToBeTested 
BSB,+c0-{ Note: --ExecutableElement name is m1 
(^B:aC7^ Note: --as=@PluggableAPT.ToBeTested(group="A") 
,rXJq|G G Note: ----m1.group=A 
I(\ 3qTe Note: --ExecutableElement name is m2 
:X*j]=/ Note: --as=@PluggableAPT.ToBeTested(group="B", owner="QQ") 
;pA;f Note: ----m2.group=B 
rhAuYn\#' Note: ----m2.owner=QQ 
'[EY14/ym Note: --ExecutableElement name is m3 
pe''2$+ Note: --as=@javax.annotation.PostConstruct 
oPXPh_.^| Round 2: 
dt^Gw|#x     input files: {} 
|5!Kg |0`     annotations: [] 
!TE5@oB     last round: true 
1A~9s<_YI  
|W=  ( 本来想用JDK6.0的Compiler API来执行上面编译命令,可是好像现在Compiler API还不支持-processor参数,运行时总报以下错误 
8-4 ?sw  
7me_%NhQ Exception in thread "main" java.lang.IllegalArgumentException: invalid flag: -processor PluggableAPT.MyAnnotationProcessor 
XWUdr6jk  
3_F;7NT=  调用Compiler API的代码是这样的 
Ar^sB3E  
c x2o JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
-M=$Qjn3M StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); 
] 9 )A#P Iterable<? extends JavaFileObject> sourcefiles = fileManager.getJavaFileObjects("Testing.java"); 
*&;xV n Set<String> options = new HashSet<String>(); 
a7>Tr! options.add("-processor PluggableAPT.MyAnnotationProcessor"); 
Rpszw ESr compiler.getTask(null, fileManager, null, options, null, sourcefiles).call(); 
S$H ?T_F   
不知道这是不是Compiler API的一个bug.
  评论这张
 
阅读(707)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017