讲一下annotation的概念先,再来讲一下怎样设计自己的annotation.
1、源文件Target.java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
其中的@interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字(会不会觉得sun有点吝啬,偏偏搞得与interface这么像).
2、源文件Retention.java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
看到这里,大家可能都模糊了,都不知道在说什么,别急,往下看一下.
在上面的文件都用到了RetentionPolicy,ElementType这两个字段,你可能就会猜到这是两个java文件.的确,这两个文件的源代码如下:
3、源文件RetentionPolicy.java
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
这是一个enum类型,共有三个值,分别是SOURCE,CLASS 和 RUNTIME.
SOURCE代表的是这个Annotation类型的信息只会保留在程序源码里,源码如果经过了编译之后,Annotation的数据就会消失,并不会保留在编译好的.class文件里面。
ClASS的意思是这个Annotation类型的信息保留在程序源码里,同时也会保留在编译好的.class文件里面,在执行的时候,并不会把这一些信息加载到虚拟机(JVM)中去.注意一下,当你没有设定一个Annotation类型的Retention值时,系统默认值是CLASS.
第三个,是RUNTIME,表示在源码、编译好的.class文件中保留信息,在执行的时候会把这一些信息加载到JVM中去的.
举一个例子,如@Override里面的Retention设为SOURCE,编译成功了就不要这一些检查的信息;相反,@Deprecated里面的Retention设为RUNTIME,表示除了在编译时会警告我们使用了哪个被Deprecated的方法,在执行的时候也可以查出该方法是否被Deprecated.
4、源文件ElementType.java
@Target里面的ElementType是用来指定Annotation类型可以用在哪一些元素上的.说明一下:TYPE(类型), FIELD(属性), METHOD(方法), PARAMETER(参数), CONSTRUCTOR(构造函数),LOCAL_VARIABLE(局部变量), ANNOTATION_TYPE,PACKAGE(包),其中的TYPE(类型)是指可以用在Class,Interface,Enum和Annotation类型上.
另外,从1的源代码可以看出,@Target自己也用了自己来声明自己,只能用在ANNOTATION_TYPE之上.
如果一个Annotation类型没有指明@Target使用在哪些元素上,那么它可以使用在任何元素之上,这里的元素指的是上面的八种类型.
举几个正确的例子:
@Target(ElementType.METHOD)
@Target(value=ElementType.METHOD)
@Target(ElementType.METHOD,ElementType.CONSTRUCTOR)
具体参考一下javadoc文档
上面一下1和2的源文件,它们都使用了@Documented,@Documented的目的就是让这一个Annotation类型的信息能够显示在javaAPI说明文档上;没有添加的话,使用javadoc生成API文档的时候就会找不到这一个类型生成的信息.
另外一点,如果需要把Annotation的数据继承给子类,那么就会用到@Inherited这一个Annotation类型.
下面讲的设计一个最简单的Annotation例子,这一例子共用四个文件;
1、Description.java
package lighter.iteye.com;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Description {
String value();
}
说明:所有的Annotation会自动继承java.lang.annotation这一个接口,所以不能再去继承别的类或是接口.
最重要的一点,Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型.
第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String.
第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:上面的例子就只有一个参数成员.
2、Name.java
package lighter.iteye.com;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//注意这里的@Target与@Description里的不同,参数成员也不同
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Name {
String originate();
String community();
}
3、JavaEyer.java
package lighter.iteye.com;
@Description("javaeye,做最棒的软件开发交流社区")
public class JavaEyer {
@Name(originate="创始人:robbin",community="javaEye")
public String getName()
{
return null;
}
@Name(originate="创始人:江南白衣",community="springside")
public String getName2()
{
return "借用两位的id一用,写这一个例子,请见谅!";
}
}
4、最后,写一个可以运行提取JavaEyer信息的类TestAnnotation
-
package lighter.iteye.com; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; public class TestAnnotation { /** * author lighter * 说明:具体关天Annotation的API的用法请参见javaDoc文档 */ public static void main(String[] args) throws Exception { String CLASS_NAME = "lighter.iteye.com.JavaEyer"; Class test = Class.forName(CLASS_NAME); Method[] method = test.getMethods(); boolean flag = test.isAnnotationPresent(Description.class); if(flag) { Description des = (Description)test.getAnnotation(Description.class); System.out.println("描述:"+des.value()); System.out.println("-----------------"); } //把JavaEyer这一类有利用到@Name的全部方法保存到Set中去 Set<Method> set = new HashSet<Method>(); for(int i=0;i<method.length;i++) { boolean otherFlag = method[i].isAnnotationPresent(Name.class); if(otherFlag) set.add(method[i]); } for(Method m: set) { Name name = m.getAnnotation(Name.class); System.out.println(name.originate()); System.out.println("创建的社区:"+name.community()); } } }
5、运行结果:
描述:javaeye,做最棒的软件开发交流社区
-----------------
创始人:robbin
创建的社区:javaEye
创始人:江南白衣
创建的社区:springside
Annotation工作原理:
Annotation与反射
在java5.0中Java.lang.reflect提供的反射API被扩充了读取运行时annotation的能力。让我们回顾一下前面所讲的:一个annotation类型被定义为runtimeretention后,它才是在运行时可见,当class文件被装载时被保存在class文件中的annotation才会被虚拟机读取。那么reflect是如何帮助我们访问class中的annotation呢?
下文将在java.lang.reflect用于annotation的新特性,其中java.lang.reflect.AnnotatedElement是重要的接口,它代表了提供查询annotation能力的程序成员。这个接口被java.lang.Package、java.lang.Class实现,并间接地被Method类、Constructor类、java.lang.reflect的Field类实现。而annotation中的方法参数可以通过Method类、Constructor类的getParameterAnnotations()方法获得。
下面的代码使用了AnnotatedElement类的isAnnotationPresent()方法判断某个方法是否具有@Unstable annotation,从而断言此方法是否稳定:
清单8:
import java.lang.reflect.*; Class c = WhizzBangClass.class; Method m = c.getMethod("whizzy", int.class, int.class); boolean unstable = m.isAnnotationPresent(Unstable.class);
isAnnotationPresent()方法对于检查marker annotation是十分有用的,因为markerannotation没有成员变量,所以我们只要知道class的方法是否使用了annotation修饰就可以了。而当处理具有成员的annotation时,我们通过使用getAnnotation()方法来获得annotation的成员信息(成员名称、成员值)。这里我们看到了一套优美的javaannotation系统:如果annotation存在,那么实现了相应的annotation类型接口的对象将被getAnnotation()方法返回,接着调用定义在annotation类型中的成员方法可以方便地获得任何成员值。
回想一下,前面介绍的@Reviews annotation,如果这个annotation类型被声明为runtime retention的话,我们通过下面的代码来访问@Reviews annotation的成员值:
清单9:
annotation实例分析AnnotatedElement target = WhizzBangClass.class; //获得被查询的AnnotatedElement // 查询AnnotatedElement的@Reviews annotation信息 Reviews annotation = target.getAnnotation(Reviews.class); // 因为@Reviews annotation类型的成员为@Review annotation类型的数组, // 所以下面声明了Review[] reviews保存@Reviews annotation类型的value成员值。 Review[] reviews = annotation.value(); // 查询每个@Review annotation的成员信息 for(Review r : reviews) { Review.Grade grade = r.grade(); String reviewer = r.reviewer(); String comment = r.comment(); System.out.printf("%s assigned a grade of %s and comment '%s'%n", reviewer, grade, comment); }
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:
package com.bjinfotech.practice.annotation.runtimeframework; import java.lang.annotation.*; /** * 用于修饰类的固有类型成员变量的annotation * @author cleverpig * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Persistent { String value() default ""; }
B.Exportable类:
清单2:
package com.bjinfotech.practice.annotation.runtimeframework; import java.lang.annotation.*; /** * 用于修饰类的类型的annotation * @author cleverpig * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Exportable { //名称 String name() default ""; //描述 String description() default ""; //省略name和description后,用来保存name值 String value() default ""; }
C.AddressForTest类:
清单3:
package com.bjinfotech.practice.annotation.runtimeframework; /** * 用于测试的地址类 * @author cleverpig * */ @Exportable("address") public class AddressForTest { //国家 @Persistent private String country=null; //省级 @Persistent private String province=null; //城市 @Persistent private String city=null; //街道 @Persistent private String street=null; //门牌 @Persistent private String doorplate=null; public AddressForTest(String country,String province, String city,String street,String doorplate){ this.country=country; this.province=province; this.city=city; this.street=street; this.doorplate=doorplate; } }
D.AddressListForTest类:
清单4:
package com.bjinfotech.practice.annotation.runtimeframework; import java.util.*; /** * 友人通讯录 * 包含:姓名、年龄、电话、住址(多个)、备注 * @author cleverpig * */ @Exportable(name="addresslist",description="address list") public class AddressListForTest { //友人姓名 @Persistent private String friendName=null; //友人年龄 @Persistent private int age=0; //友人电话 @Persistent private ArrayList<String> telephone=null; //友人住址:家庭、单位 @Persistent private ArrayList<AddressForTest> AddressForText=null; //备注 @Persistent private String note=null; public AddressListForTest(String name,int age, ArrayList<String> telephoneList, ArrayList<AddressForTest> addressList, String note){ this.friendName=name; this.age=age; this.telephone=new ArrayList<String>(telephoneList); this.AddressForText=new ArrayList<AddressForTest>(addressList); this.note=note; } }
E.ExportToXml类:
清单5:
package com.bjinfotech.practice.annotation.runtimeframework; import java.lang.reflect.Field; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.ArrayList; /** * 将具有Exportable Annotation的对象转换为xml格式文本 * @author cleverpig * */ public class ExportToXml { /** * 返回对象的成员变量的值(字符串类型) * @param field 对象的成员变量 * @param fieldTypeClass 对象的类型 * @param obj 对象 * @return 对象的成员变量的值(字符串类型) */ private String getFieldValue(Field field,Class fieldTypeClass,Object obj){ String value=null; try{ if (fieldTypeClass==String.class){ value=(String)field.get(obj); } else if (fieldTypeClass==int.class){ value=Integer.toString(field.getInt(obj)); } else if (fieldTypeClass==long.class){ value=Long.toString(field.getLong(obj)); } else if (fieldTypeClass==short.class){ value=Short.toString(field.getShort(obj)); } else if (fieldTypeClass==float.class){ value=Float.toString(field.getFloat(obj)); } else if (fieldTypeClass==double.class){ value=Double.toString(field.getDouble(obj)); } else if (fieldTypeClass==byte.class){ value=Byte.toString(field.getByte(obj)); } else if (fieldTypeClass==char.class){ value=Character.toString(field.getChar(obj)); } else if (fieldTypeClass==boolean.class){ value=Boolean.toString(field.getBoolean(obj)); } } catch(Exception ex){ ex.printStackTrace(); value=null; } return value; } /** * 输出对象的字段,当对象的字段为Collection或者Map类型时,要调用exportObject方法继续处理 * @param obj 被处理的对象 * @throws Exception */ public void exportFields(Object obj) throws Exception{ Exportable exportable=obj.getClass().getAnnotation(Exportable.class); if (exportable!=null){ if (exportable.value().length()>0){ // System.out.println("Class annotation Name:"+exportable.value()); } else{ // System.out.println("Class annotation Name:"+exportable.name()); } } else{ // System.out.println(obj.getClass()+"类不是使用Exportable标注过的"); } //取出对象的成员变量 Field[] fields=obj.getClass().getDeclaredFields(); for(Field field:fields){ //获得成员变量的标注 Persistent fieldAnnotation=field.getAnnotation(Persistent.class); if (fieldAnnotation==null){ continue; } //重要:避免java虚拟机检查对私有成员的访问权限 field.setAccessible(true); Class typeClass=field.getType(); String name=field.getName(); String value=getFieldValue(field,typeClass,obj); //如果获得成员变量的值,则输出 if (value!=null){ System.out.println(getIndent()+"<"+name+">\n" +getIndent()+"\t"+value+"\n"+getIndent()+"</"+name+">"); } //处理成员变量中类型为Collection或Map else if ((field.get(obj) instanceof Collection)|| (field.get(obj) instanceof Map)){ exportObject(field.get(obj)); } else{ exportObject(field.get(obj)); } } } //缩进深度 int levelDepth=0; //防止循环引用的检查者,循环引用现象如:a包含b,而b又包含a Collection<Object> cyclicChecker=new ArrayList<Object>(); /** * 返回缩进字符串 * @return */ private String getIndent(){ String s=""; for(int i=0;i<levelDepth;i++){ s+="\t"; } return s; } /** * 输出对象,如果对象类型为Collection和Map类型,则需要递归调用exportObject进行处理 * @param obj * @throws Exception */ public void exportObject(Object obj) throws Exception{ Exportable exportable=null; String elementName=null; //循环引用现象处理 if (cyclicChecker.contains(obj)){ return; } cyclicChecker.add(obj); //首先处理Collection和Map类型 if (obj instanceof Collection){ for(Iterator i=((Collection)obj).iterator();i.hasNext();){ exportObject(i.next()); } } else if (obj instanceof Map){ for(Iterator i=((Map)obj).keySet().iterator();i.hasNext();){ exportObject(i.next()); } } else{ exportable=obj.getClass().getAnnotation(Exportable.class); //如果obj已经被Exportable Annotation修饰过了(注意annotation是具有继承性的), //则使用其name作为输出xml的元素name if (exportable!=null){ if (exportable.value().length()>0){ elementName=exportable.value(); } else{ elementName=exportable.name(); } } //未被修饰或者Exportable Annotation的值为空字符串, //则使用类名作为输出xml的元素name if (exportable==null||elementName.length()==0){ elementName=obj.getClass().getSimpleName(); } //输出xml元素头 System.out.println(getIndent()+"<"+elementName+">"); levelDepth++; //如果没有被修饰,则直接输出其toString()作为元素值 if (exportable==null){ System.out.println(getIndent()+obj.toString()); } //否则将对象的成员变量导出为xml else{ exportFields(obj); } levelDepth--; //输出xml元素结尾 System.out.println(getIndent()+"</"+elementName+">"); } cyclicChecker.remove(obj); } public static void main(String[] argv){ try{ AddressForTest ad=new AddressForTest("China","Beijing", "Beijing","winnerStreet","10"); ExportToXml test=new ExportToXml(); ArrayList<String> telephoneList=new ArrayList<String>(); telephoneList.add("66608888"); telephoneList.add("66608889"); ArrayList<AddressForTest> adList=new ArrayList<AddressForTest>(); adList.add(ad); AddressListForTest adl=new AddressListForTest("coolBoy", 18,telephoneList,adList,"some words"); test.exportObject(adl); } catch(Exception ex){ ex.printStackTrace(); } } }
在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:
<addresslist> <friendName> coolBoy </friendName> <age> 18 </age> <String> 66608888 </String> <String> 66608889 </String> <address> <country> China </country> <province> Beijing </province> <city> Beijing </city> <street> winnerStreet </street> <doorplate> 10 </doorplate> </address> <note> some words </note> </addresslist>
java annotation processing tools(APT)实例解析
------使用APT处理Annotation
转自:http://blog.sina.com.cn/s/blog_4c925dca0100hsyt.html
APT(Annotation processing tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。
Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件.
使用APT主要的目的是简化开发者的工作量,因为APT可以编译程序源代码的同时,生成一些附属文件(比如源文件,类文件,程序发布描述文件等),这些附属文件的内容也都是与源代码相关的,换句话说,使用APT可以代替传统的对代码信息和附属文件的维护工作。
如果有过Hibernate开发经验的朋友可能知道每写一个Java文件,还必须额外地维护一个Hibernate映射文件(一个名为*.hbm.xml的文件,当然可以有一些工具可以自动生成),下面将使用Annotation来简化这步操作。
为了使用系统的apt工具来读取源文件中的Annotation,程序员必须自定义一个Annotation处理器,编写Annotation处理器需要使用JDK lib目录中的tools.jar 里的如下4个包.
com.sun.mirror.apt:和APT交互的接口
com.sun.mirror.declaration:包含各种封装类成员,类方法,类声明的接口。
com.sun.mirror.type:包含各种封装源代码中程序元素的接口。
com.sun.mirror.util:提供了用于处理类型和声明的一些工具。
每个Annotation处理器需要实现com.sun.mirror.apt包下的AnnotationProcessor接口,这个接口中定义了一个"process"方法,该方法是由apt调用Annotation处理器时将被用到的。
一个Annotation处理器可以处理一种或多种Annotation类型。
1.通常情况下,Annotation处理器实例是由其相应的工厂返回,Annotation处理器工厂应该实现AnnotationProcessorFactory接口,APT将调用工厂类的getProcessorFor方法来获得Annotation处理器。
2.在调用过程中,APT将提供给工厂类一个AnnotationProcessorEnvironment对象.
3.AnnotationProcessorEnvironment对象是APT工具与注释环境通信的途径。
使用APT工具来处理源文件时,APT首先检测在源代码文件中包含哪些Annotation,然后APT将查找所需的处理器工厂,并由工厂来返回相应的Annotation处理器。如果该处理器工厂支持这些Annotaion,处理器工厂返回的Annotaion处理器将会处理这些Annotation,如果生成的源文件中再次包含Annotaion,APT将会重复上面过程,直至没有新文件生成。
为了说明使用APT来根据源文件中的注释来生成额外的文件,下面将定义三个Annotation类型,分别用于修饰持久化类,标识属性和普通属性。
程序清单
修饰表属性
import java.lang.annotation.*;
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Persistent
{
}
修饰标识属性
import java.lang.annotation.*;
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface IdProperty
{
}
修饰普通成员变量的Annotation
import java.lang.annotation.*;
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Property
{
}
定义了三个Annotation之后,下面我们提供一个简单的Java类文件,这个Java类文件使用了上面三个Annotation来修饰
@Persistent(table="persons_table")
public class Person
{
}
上面Person类是一个非常普通的Java类,但这个普通的Java类使用了@Persistent,@IdProperty,@IdPropery三个Annotation。下面我们为这三个Annotation提供了一个Annotation处理器,该处理器的功能是根据注释来生成一个Hibernate的映射文件.
程序清单
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.*;
import com.sun.mirror.util.*;
import java.beans.*;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
public class HibernateAnnotationProce
{
}
上面的Annotation处理器比较简单,与前面通过反射来获取Annotation信息不同的是,这个Annotation处理器使用AnnotationProcessorEnvir
TypeDeclaration又包含了如下三个常用方法来获得对应的程序元素。
getFields:获取该类声明里的所有成员变量声明,返回值是集合元素FieldDeclaration的集合
getMethods:获取该类声明里的所有成员声明,返回值是集合元素MethodDeclaration的集合
getPackage:获取该类声明里的包声明,返回值是TypeDeclaration
上面三个方法返回的TypeDeclaration,FieldDeclaration,MethodDeclaration都可调用getAnnotation方法来访问修饰它们的Annotation,上面程序中就是获取不同程序元素的Annotation的代码。
提供了上面的Annotation处理器类之后,还应该为该Annotation处理器提供一个处理工厂,处理工厂负责决定该处理器支持哪些Annotation,并通过getProcessorFor方法来生成一个Annotation处理哭对象。
程序清单如下
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.*;
import com.sun.mirror.util.*;
import java.beans.*;
import java.io.*;
import java.util.*;
public class HibernateAnnotationFacto
{
}
提供了上面的处理器工厂后,就可以使用APT工具来处理上面的Person.java源文件,并根据该源文件来生成一个XML文件。 APT工具位于JDK的安装路径的bin路径下。。
运行APT命令时,可以使用-factory选项来指定处理器工厂类
如下所示
rem 使用HibernateAnnotationFacto
apt -factory HibernateAnnotationFacto
使用APT工具,HibernateAnnotationFacto
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
<hibernate-mapping>
</hibernate-mapping>
总结