版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:cleverpig(作者的Blog:http://blog.matrix.org.cn/page/cleverpig)
原文:http://www.matrix.org.cn/resource/article/44/44062_Java+Annotation+Apt.html
关键字:java,annotation,apt

 

一、摘要:
《java annotation高级应用》具体实例化解释annotation和annotation processing tool(APT)的使用。望能对各位的有所帮助。本文列举了用于演示annotation的BRFW演示框架、演示APT的apt代码实例,并对其进行较为深度的分析,希望大家多多提意见。
二、annotation实例分析
1.BRFW(Beaninfo Runtime FrameWork)定义:
本人编写的一个annotation功能演示框架。顾名思义,BRFW就是在运行时取得bean信息的框架。
2.BRFW的功能:
A.源代码级annotation:在bean的源代码中使用annotation定义bean的信息;
B.运行时获取bean数据:在运行时分析bean class中的annotation,并将当前bean class中field信息取出,功能类似xdoclet;
C.运行时bean数据的xml绑定:将获得的bean数据构造为xml文件格式展现。熟悉j2ee的朋友知道,这个功能类似jaxb。

3.BRFW框架:
BRFW主要包含以下几个类:
A.Persistent类:定义了用于修饰类的固有类型成员变量的annotation。
B.Exportable类:定义了用于修饰Class的类型的annotation。
C.ExportToXml类:核心类,用于完成BRFW的主要功能:将具有Exportable Annotation的bean对象转换为xml格式文本。
D.AddressForTest类:被A和B修饰过的用于测试目的的地址bean类。其中包含了地址定义所必需的信息:国家、省级、城市、街道、门牌等。
E.AddressListForTest类:被A和B修饰过的友人通讯录bean类。其中包含了通讯录所必备的信息:友人姓名、年龄、电话、住址(成员为AddressForTest类型的ArrayList)、备注。需要说明的是电话这个bean成员变量是由字符串类型组成的ArrayList类型。由于朋友的住址可能不唯一,故这里的住址为由AddressForTest类型组成的ArrayList。
从上面的列表中,可以发现A、B用于修饰bean类和其类成员;C主要用于取出bean类的数据并将其作xml绑定,代码中使用了E作为测试类;E中可能包含着多个D。
在了解了这个简单框架后,我们来看一下BRFW的代码吧!
4.BRFW源代码分析:
A.Persistent类:
清单1:
 

  1. package com.bjinfotech.practice.annotation.runtimeframework;  
  2.  
  3. import java.lang.annotation.*;  
  4.  
  5. /**  
  6.  * 用于修饰类的固有类型成员变量的annotation  
  7.  * @author cleverpig  
  8.  *  
  9.  */ 
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Target(ElementType.FIELD)  
  12. public @interface Persistent {   
  13.         String value() default "";  

 B.Exportable类:
清单2:
 

 

  1. package com.bjinfotech.practice.annotation.runtimeframework;  
  2.  
  3. import java.lang.annotation.*;  
  4.  
  5. /**  
  6.  * 用于修饰类的类型的annotation  
  7.  * @author cleverpig  
  8.  *  
  9.  */ 
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Target(ElementType.TYPE)  
  12. public @interface Exportable {  
  13.         //名称  
  14.         String name() default "";  
  15.         //描述  
  16.         String description() default "";  
  17.         //省略name和description后,用来保存name值  
  18.         String value() default "";  
  19.           

C.AddressForTest类:
清单3:
 

  1. package com.bjinfotech.practice.annotation.runtimeframework;  
  2.  
  3. /**  
  4.  * 用于测试的地址类  
  5.  * @author cleverpig  
  6.  *  
  7.  */ 
  8. @Exportable("address")  
  9. public class AddressForTest {  
  10.         //国家  
  11.         @Persistent 
  12.         private String country=null;  
  13.           
  14.         //省级  
  15.         @Persistent 
  16.         private String province=null;  
  17.           
  18.         //城市  
  19.         @Persistent 
  20.         private String city=null;  
  21.           
  22.         //街道  
  23.         @Persistent 
  24.         private String street=null;  
  25.  
  26.         //门牌  
  27.         @Persistent 
  28.         private String doorplate=null;  
  29.           
  30.         public AddressForTest(String country,String province,  
  31.                         String city,String street,String doorplate){  
  32.                 this.country=country;  
  33.                 this.province=province;  
  34.                 this.city=city;  
  35.                 this.street=street;  
  36.                 this.doorplate=doorplate;  
  37.         }  
  38.           

D.AddressListForTest类:
清单4:
 

  1. package com.bjinfotech.practice.annotation.runtimeframework;  
  2.  
  3. import java.util.*;  
  4.  
  5. /**  
  6.  * 友人通讯录  
  7.  * 包含:姓名、年龄、电话、住址(多个)、备注  
  8.  * @author cleverpig  
  9.  *  
  10.  */ 
  11. @Exportable(name="addresslist",description="address list")  
  12. public class AddressListForTest {  
  13.         //友人姓名  
  14.         @Persistent 
  15.         private String friendName=null;  
  16.           
  17.         //友人年龄  
  18.         @Persistent 
  19.         private int age=0;  
  20.           
  21.         //友人电话  
  22.         @Persistent 
  23.         private ArrayList<String> telephone=null;  
  24.           
  25.         //友人住址:家庭、单位  
  26.         @Persistent 
  27.         private ArrayList<AddressForTest> AddressForText=null;  
  28.           
  29.         //备注  
  30.         @Persistent 
  31.         private String note=null;  
  32.           
  33.         public AddressListForTest(String name,int age,  
  34.                         ArrayList<String> telephoneList,   
  35.                         ArrayList<AddressForTest> addressList,  
  36.                         String note){  
  37.                 this.friendName=name;  
  38.                 this.age=age;  
  39.                 this.telephone=new ArrayList<String>(telephoneList);  
  40.                 this.AddressForText=new ArrayList<AddressForTest>(addressList);  
  41.                 this.note=note;  
  42.                   
  43.         }  

E.ExportToXml类:
清单5:
 

  1. package com.bjinfotech.practice.annotation.runtimeframework;  
  2.  
  3. import java.lang.reflect.Field;  
  4. import java.util.Collection;  
  5. import java.util.Iterator;  
  6. import java.util.Map;  
  7. import java.util.ArrayList;  
  8.  
  9. /**  
  10.  * 将具有Exportable Annotation的对象转换为xml格式文本   
  11.  * @author cleverpig  
  12.  *  
  13.  */ 
  14. public class ExportToXml {  
  15.         /**  
  16.          * 返回对象的成员变量的值(字符串类型)  
  17.          * @param field 对象的成员变量  
  18.          * @param fieldTypeClass 对象的类型  
  19.          * @param obj 对象  
  20.          * @return 对象的成员变量的值(字符串类型)  
  21.          */ 
  22.         private String getFieldValue(Field field,Class fieldTypeClass,Object obj){  
  23.                 String value=null;  
  24.                   
  25.                 try{  
  26.                         if (fieldTypeClass==String.class){  
  27.                                 value=(String)field.get(obj);  
  28.                         }  
  29.                         else if (fieldTypeClass==int.class){  
  30.                                 value=Integer.toString(field.getInt(obj));  
  31.                         }  
  32.                         else if (fieldTypeClass==long.class){  
  33.                                 value=Long.toString(field.getLong(obj));  
  34.                         }  
  35.                         else if (fieldTypeClass==short.class){  
  36.                                 value=Short.toString(field.getShort(obj));  
  37.                         }  
  38.                         else if (fieldTypeClass==float.class){  
  39.                                 value=Float.toString(field.getFloat(obj));  
  40.                         }  
  41.                         else if (fieldTypeClass==double.class){  
  42.                                 value=Double.toString(field.getDouble(obj));  
  43.                         }  
  44.                         else if (fieldTypeClass==byte.class){  
  45.                                 value=Byte.toString(field.getByte(obj));  
  46.                         }  
  47.                         else if (fieldTypeClass==char.class){  
  48.                                 value=Character.toString(field.getChar(obj));  
  49.                         }  
  50.                         else if (fieldTypeClass==boolean.class){  
  51.                                 value=Boolean.toString(field.getBoolean(obj));  
  52.                         }  
  53.                 }  
  54.                 catch(Exception ex){  
  55.                         ex.printStackTrace();  
  56.                         value=null;  
  57.                 }  
  58.                 return value;  
  59.         }  
  60.           
  61.         /**  
  62.          * 输出对象的字段,当对象的字段为Collection或者Map类型时,要调用exportObject方法继续处理  
  63.          * @param obj 被处理的对象  
  64.          * @throws Exception  
  65.          */ 
  66.         public void exportFields(Object obj) throws Exception{  
  67.                 Exportable exportable=obj.getClass().getAnnotation(Exportable.class);          
  68.                 if (exportable!=null){  
  69.                         if (exportable.value().length()>0){  
  70. //                                System.out.println("Class annotation Name:"+exportable.value());  
  71.                         }  
  72.                         else{  
  73. //                                System.out.println("Class annotation Name:"+exportable.name());  
  74.                         }  
  75.                 }  
  76.                 else{  
  77. //                        System.out.println(obj.getClass()+"类不是使用Exportable标注过的");  
  78.                 }  
  79.                   
  80.                 //取出对象的成员变量  
  81.                 Field[] fields=obj.getClass().getDeclaredFields();  
  82.                   
  83.                 for(Field field:fields){  
  84.                         //获得成员变量的标注  
  85.                         Persistent fieldAnnotation=field.getAnnotation(Persistent.class);  
  86.                         if (fieldAnnotation==null){  
  87.                                 continue;  
  88.                         }  
  89.                         //重要:避免java虚拟机检查对私有成员的访问权限  
  90.                         field.setAccessible(true);  
  91.                         Class typeClass=field.getType();  
  92.                         String name=field.getName();  
  93.                         String value=getFieldValue(field,typeClass,obj);  
  94.                           
  95.                         //如果获得成员变量的值,则输出  
  96.                         if (value!=null){  
  97.                                 System.out.println(getIndent()+"<"+name+">\n" 
  98.                                                 +getIndent()+"\t"+value+"\n"+getIndent()+"</"+name+">");  
  99.                         }  
  100.                         //处理成员变量中类型为Collection或Map  
  101.                         else if ((field.get(obj) instanceof Collection)||  
  102.                                         (field.get(obj) instanceof Map)){  
  103.                                 exportObject(field.get(obj));  
  104.                         }  
  105.                         else{  
  106.                                 exportObject(field.get(obj));  
  107.                         }  
  108.                           
  109.                 }  
  110.         }  
  111.           
  112.         //缩进深度  
  113.         int levelDepth=0;  
  114.         //防止循环引用的检查者,循环引用现象如:a包含b,而b又包含a  
  115.         Collection<Object> cyclicChecker=new ArrayList<Object>();  
  116.           
  117.         /**  
  118.          * 返回缩进字符串  
  119.          * @return  
  120.          */ 
  121.         private String getIndent(){  
  122.                 String s="";  
  123.                 for(int i=0;i<levelDepth;i++){  
  124.                         s+="\t";  
  125.                 }  
  126.                 return s;  
  127.         }  
  128.         /**  
  129.          * 输出对象,如果对象类型为Collection和Map类型,则需要递归调用exportObject进行处理  
  130.          * @param obj  
  131.          * @throws Exception  
  132.          */ 
  133.         public void exportObject(Object obj) throws Exception{  
  134.                 Exportable exportable=null;  
  135.                 String elementName=null;  
  136.                   
  137.                 //循环引用现象处理  
  138.                 if (cyclicChecker.contains(obj)){  
  139.                         return;  
  140.                 }  
  141.                   
  142.                 cyclicChecker.add(obj);  
  143.                   
  144.                 //首先处理Collection和Map类型  
  145.                 if (obj instanceof Collection){  
  146.                         for(Iterator i=((Collection)obj).iterator();i.hasNext();){  
  147.                                 exportObject(i.next());  
  148.                         }  
  149.                 }  
  150.                 else if (obj instanceof Map){  
  151.                         for(Iterator i=((Map)obj).keySet().iterator();i.hasNext();){  
  152.                                 exportObject(i.next());  
  153.                         }  
  154.                 }  
  155.                 else{  
  156.  
  157.                         exportable=obj.getClass().getAnnotation(Exportable.class);  
  158.                         //如果obj已经被Exportable Annotation修饰过了(注意annotation是具有继承性的),  
  159.                         //则使用其name作为输出xml的元素name  
  160.                         if (exportable!=null){  
  161.                                 if (exportable.value().length()>0){  
  162.                                         elementName=exportable.value();  
  163.                                 }  
  164.                                 else{  
  165.                                         elementName=exportable.name();  
  166.                                 }  
  167.                         }  
  168.                         //未被修饰或者Exportable Annotation的值为空字符串,  
  169.                         //则使用类名作为输出xml的元素name  
  170.                         if (exportable==null||elementName.length()==0){  
  171.                                 elementName=obj.getClass().getSimpleName();  
  172.                         }  
  173.                         //输出xml元素头  
  174.                         System.out.println(getIndent()+"<"+elementName+">");  
  175.                         levelDepth++;  
  176.                         //如果没有被修饰,则直接输出其toString()作为元素值  
  177.                         if (exportable==null){  
  178.                                 System.out.println(getIndent()+obj.toString());  
  179.                         }  
  180.                         //否则将对象的成员变量导出为xml  
  181.                         else{  
  182.                                 exportFields(obj);  
  183.                         }  
  184.                         levelDepth--;  
  185.                         //输出xml元素结尾  
  186.                         System.out.println(getIndent()+"</"+elementName+">");  
  187.                           
  188.                 }  
  189.                 cyclicChecker.remove(obj);  
  190.         }  
  191.           
  192.         public static void main(String[] argv){  
  193.                 try{  
  194.                         AddressForTest ad=new AddressForTest("China","Beijing",  
  195.                                         "Beijing","winnerStreet","10");  
  196.                           
  197.                         ExportToXml test=new ExportToXml();  
  198.                           
  199.                         ArrayList<String> telephoneList=new ArrayList<String>();  
  200.                         telephoneList.add("66608888");  
  201.                         telephoneList.add("66608889");  
  202.                           
  203.                         ArrayList<AddressForTest> adList=new ArrayList<AddressForTest>();  
  204.                         adList.add(ad);  
  205.                           
  206.                         AddressListForTest adl=new AddressListForTest("coolBoy",  
  207.                                         18,telephoneList,adList,"some words");  
  208.                           
  209.                         test.exportObject(adl);  
  210.                 }  
  211.                 catch(Exception ex){  
  212.                         ex.printStackTrace();  
  213.                 }  
  214.         }  

在ExportToXml类之前的类比较简单,这里必须说明一下ExportToXml类:此类的核心函数是exportObject和exportFields方法,前者输出对象的xml信息,后者输出对象成员变量的信息。由于对象类型和成员类型的多样性,所以采取了以下的逻辑:

在exportObject方法中,当对象类型为Collection和Map类型时,则需要递归调用exportObject进行处理;
而如果对象类型不是Collection和Map类型的话,将判断对象类是否被Exportable annotation修饰过:
如果没有被修饰,则直接输出<对象类名>对象.toString()</对象类名>作为xml绑定结果的一部分;
如果被修饰过,则需要调用exportFields方法对对象的成员变量进行xml绑定。

在exportFields方法中,首先取出对象的所有成员,然后获得被Persisitent annotation修饰的成员。在其后的一句:field.setAccessible(true)是很重要的,因为bean类定义中的成员访问修饰都是private,所以为了避免java虚拟机检查对私有成员的访问权限,加上这一句是必需的。接着后面的语句便是输出<成员名>成员值</成员名>这样的xml结构。像在exportObject方法中一般,仍然需要判断成员类型是否为Collection和Map类型,如果为上述两种类型之一,则要在exportFields中再次调用exportObject来处理这个成员。

在main方法中,本人编写了一段演示代码:建立了一个由单个友人地址类(AddressForTest)组成的ArrayList作为通讯录类(AddressForTest)的成员的通讯录对象,并且输出这个对象的xml绑定,运行结果如下:

清单6:
 

  1. <addresslist>  
  2.         <friendName>  
  3.                 coolBoy  
  4.         </friendName>  
  5.         <age>  
  6.                 18 
  7.         </age>  
  8.         <String>  
  9.                 66608888 
  10.         </String>  
  11.         <String>  
  12.                 66608889 
  13.         </String>  
  14.         <address>  
  15.                 <country>  
  16.                         China  
  17.                 </country>  
  18.                 <province>  
  19.                         Beijing  
  20.                 </province>  
  21.                 <city>  
  22.                         Beijing  
  23.                 </city>  
  24.                 <street>  
  25.                         winnerStreet  
  26.                 </street>  
  27.                 <doorplate>  
  28.                         10 
  29.                 </doorplate>  
  30.         </address>  
  31.         <note>  
  32.                 some words  
  33.         </note>  
  34. </addresslist> 

 三、APT实例分析:
1.何谓APT?
根据sun官方的解释,APT(annotation processing tool)是一个命令行工具,它对源代码文件进行检测找出其中的annotation后,使用annotation processors来处理annotation。而annotation processors使用了一套反射API并具备对JSR175规范的支持。
annotation processors处理annotation的基本过程如下:首先,APT运行annotation processors根据提供的源文件中的annotation生成源代码文件和其它的文件(文件具体内容由annotation processors的编写者决定),接着APT将生成的源代码文件和提供的源文件进行编译生成类文件。
简单的和前面所讲的annotation实例BRFW相比,APT就像一个在编译时处理annotation的javac。而且从sun开发者的blog中看到,java1.6 beta版中已将APT的功能写入到了javac中,这样只要执行带有特定参数的javac就能达到APT的功能。

2.为何使用APT?
使用APT主要目的是简化开发者的工作量,因为APT可以在编译程序源代码的同时,生成一些附属文件(比如源文件、类文件、程序发布描述文字等),这些附属文件的内容也都是与源代码相关的。换句话说,使用APT就是代替了传统的对代码信息和附属文件的维护工作。使用过hibernate或者beehive等软件的朋友可能深有体会。APT可以在编译生成代码类的同时将相关的文件写好,比如在使用beehive时,在代码中使用annotation声明了许多struct要用到的配置信息,而在编译后,这些信息会被APT以struct配置文件的方式存放。

3.如何定义processor?
A.APT工作过程:
从整个过程来讲,首先APT检测在源代码文件中哪些annotation存在。然后APT将查找我们编写的annotation processor factories类,并且要求factories类提供处理源文件中所涉及的annotation的annotation processor。接下来,一个合适的annotation processors将被执行,如果在processors生成源代码文件时,该文件中含有annotation,则APT将重复上面的过程直到没有新文件生成。

B.编写annotation processors:
编写一个annotation processors需要使用java1.5 lib目录中的tools.jar提供的以下4个包:
com.sun.mirror.apt: 和APT交互的接口;
com.sun.mirror.declaration: 用于模式化类成员、类方法、类声明的接口;
com.sun.mirror.type: 用于模式化源代码中类型的接口;
com.sun.mirror.util: 提供了用于处理类型和声明的一些工具。

每个processor实现了在com.sun.mirror.apt包中的AnnotationProcessor接口,这个接口有一个名为“process”的方法,该方法是在APT调用processor时将被用到的。一个processor可以处理一种或者多种annotation类型。
一个processor实例被其相应的工厂返回,此工厂为AnnotationProcessorFactory接口的实现。APT将调用工厂类的getProcessorFor方法来获得processor。在调用过程中,APT将提供给工厂类一个AnnotationProcessorEnvironment 类型的processor环境类对象,在这个环境对象中,processor将找到其执行所需要的每件东西,包括对所操作的程序结构的参考,与APT通讯并合作一同完成新文件的建立和警告/错误信息的传输。

提供工厂类有两个方式:通过APT的“-factory”命令行参数提供,或者让工厂类在APT的发现过程中被自动定位(关于发现过程详细介绍请看http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html)。前者对于一个已知的factory来讲是一种主动而又简单的方式;而后者则是需要在jar文件的META-INF/services目录中提供一个特定的发现路径:
在包含factory类的jar文件中作以下的操作:在META-INF/services目录中建立一个名为com.sun.mirror.apt.AnnotationProcessorFactory 的UTF-8编码文件,在文件中写入所有要使用到的factory类全名,每个类为一个单独行。

4.一个简单的APT实例分析:
A.实例构成:
Review类:定义Review Annotation;
ReviewProcessorFactory类:生成ReviewProcessor的工厂类;
ReviewProcessor类:定义处理Review annotation的Processor;
ReviewDeclarationVisitor类:定义Review annotation声明访问者,ReviewProcessor将要使用之对Class进行访问。
runapt.bat:定义了使用自定义的ReviewProcessor对Review类源代码文件进行处理的APT命令行。

B.Review类:
清单7:
 

  1. <PRE class=java name="code">package com.bjinfotech.practice.annotation.apt;  
  2.  
  3. /**  
  4.  * 定义Review Annotation  
  5.  * @author cleverpig  
  6.  *  
  7.  */ 
  8. public @interface Review {  
  9.         public static enum TypeEnum{EXCELLENT,NICE,NORMAL,BAD};  
  10.         TypeEnum type();  
  11.         String name() default "Review";  
  12. }  
  13.  
  14.  
  15. </PRE><BR> 

C.ReviewProcessorFactory类:

清单8:
 

  1. package com.bjinfotech.practice.annotation.apt;  
  2.  
  3. import java.util.Collection;  
  4. import java.util.Set;  
  5. import java.util.Arrays;  
  6. import com.sun.mirror.apt.*;  
  7. import com.sun.mirror.declaration.AnnotationTypeDeclaration;  
  8. import com.sun.mirror.apt.AnnotationProcessorEnvironment;  
  9. //请注意为了方便,使用了静态import  
  10. import static java.util.Collections.unmodifiableCollection;  
  11. import static java.util.Collections.emptySet;  
  12.  
  13. /**  
  14.  * 生成ReviewProcessor的工厂类  
  15.  * @author cleverpig  
  16.  *  
  17.  */ 
  18. public class ReviewProcessorFactory implements AnnotationProcessorFactory{  
  19.         /**  
  20.          * 获得针对某个(些)类型声明定义的Processor  
  21.          * @param atds 类型声明集合  
  22.          * @param env processor环境  
  23.          */ 
  24.         public AnnotationProcessor getProcessorFor(  
  25.                         Set<AnnotationTypeDeclaration> atds,   
  26.                         AnnotationProcessorEnvironment env){  
  27.                 return new ReviewProcessor(env);  
  28.         }  
  29.         /**  
  30.          * 定义processor所支持的annotation类型  
  31.          * @return processor所支持的annotation类型的集合  
  32.          */ 
  33.         public Collection<String>         supportedAnnotationTypes(){  
  34.                 //“*”表示支持所有的annotation类型  
  35.                 //当然也可以修改为“foo.bar.*”、“foo.bar.Baz”,来对所支持的类型进行修饰  
  36.             return unmodifiableCollection(Arrays.asList("*"));  
  37.     }  
  38.           
  39.         /**  
  40.          * 定义processor支持的选项  
  41.          * @return processor支持选项的集合  
  42.          */ 
  43.         public Collection<String>         supportedOptions(){  
  44.                 //返回空集合  
  45.             return emptySet();  
  46.     }  
  47.           
  48.         public static void main(String[] argv){  
  49.                 System.out.println("ok");  
  50.         }  

D.ReviewProcessor类:
清单9:
 

  1. package com.bjinfotech.practice.annotation.apt;  
  2.  
  3. import com.sun.mirror.apt.AnnotationProcessor;  
  4. import com.sun.mirror.apt.AnnotationProcessorEnvironment;  
  5. import com.sun.mirror.declaration.TypeDeclaration;  
  6. import com.sun.mirror.util.DeclarationVisitors;  
  7. import com.sun.mirror.util.DeclarationVisitor;  
  8.  
  9. /**  
  10.  * 定义Review annotation的Processor  
  11.  * @author cleverpig  
  12.  *  
  13.  */ 
  14. public class ReviewProcessor implements AnnotationProcessor{  
  15.         //Processor所工作的环境  
  16.         AnnotationProcessorEnvironment env=null;  
  17.           
  18.         /**  
  19.          * 构造方法  
  20.          * @param env 传入processor环境  
  21.          */ 
  22.         public ReviewProcessor(AnnotationProcessorEnvironment env){  
  23.                 this.env=env;  
  24.         }  
  25.           
  26.         /**  
  27.          * 处理方法:查询processor环境中的类型声明,  
  28.          */ 
  29.         public void process(){  
  30.                 //查询processor环境中的类型声明  
  31.                 for(TypeDeclaration type:env.getSpecifiedTypeDeclarations()){  
  32.                         //返回对类进行扫描、访问其声明时使用的DeclarationVisitor,  
  33.                         //传入参数:new ReviewDeclarationVisitor(),为扫描开始前进行的对类声明的处理  
  34.                         //        DeclarationVisitors.NO_OP,表示在扫描完成时进行的对类声明不做任何处理  
  35.                         DeclarationVisitor visitor=DeclarationVisitors.getDeclarationScanner(  
  36.                                         new ReviewDeclarationVisitor(),DeclarationVisitors.NO_OP);  
  37.                         //应用DeclarationVisitor到类型  
  38.                         type.accept(visitor);  
  39.                 }  
  40.         }  

E.ReviewDeclarationVisitor类:
清单10:
 

  1. package com.bjinfotech.practice.annotation.apt;  
  2.  
  3. import com.sun.mirror.util.*;  
  4. import com.sun.mirror.declaration.*;  
  5.  
  6. /**  
  7.  * 定义Review annotation声明访问者  
  8.  * @author cleverpig  
  9.  *  
  10.  */ 
  11. public class ReviewDeclarationVisitor extends SimpleDeclarationVisitor{  
  12.         /**  
  13.          * 定义访问类声明的方法:打印类声明的全名  
  14.          * @param cd 类声明对象  
  15.          */ 
  16.         public void visitClassDeclaration(ClassDeclaration cd){  
  17.                 System.out.println("获取Class声明:"+cd.getQualifiedName());  
  18.         }  
  19.           
  20.         public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration atd){  
  21.                 System.out.println("获取Annotation类型声明:"+atd.getSimpleName());  
  22.         }  
  23.           
  24.         public void visitAnnotationTypeElementDeclaration(AnnotationTypeElementDeclaration aed){  
  25.                 System.out.println("获取Annotation类型元素声明:"+aed.getSimpleName());  
  26.         }  

F.runapt.bat文件内容如下:
清单11:
 

  1. E:  
  2. rem 项目根目录  
  3. set PROJECT_ROOT=E:\eclipse3.1RC3\workspace\tigerFeaturePractice  
  4. rem 包目录路径  
  5. set PACKAGEPATH=com\bjinfotech\practice\annotation\apt  
  6. rem 运行根路径  
  7. set RUN_ROOT=%PROJECT_ROOT%\build  
  8. rem 源文件所在目录路径  
  9. set SRC_ROOT=%PROJECT_ROOT%\test  
  10. rem 设置Classpath  
  11. set CLASSPATH=.;%JAVA_HOME%;%JAVA_HOME%/lib/tools.jar;%RUN_ROOT%  
  12.  
  13. cd %SRC_ROOT%\%PACKAGEPATH%  
  14. apt -nocompile -factory com.bjinfotech.practice.annotation.apt.ReviewProcessorFactory  ./*.java 

四、参考资源:
http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html
作者的Blog:http://blog.matrix.org.cn/page/cleverpig