Java中Annotation(注释)系列学习笔记(4)

【转】Java中Annotation(注释)系列学习笔记(4)

(四)使用APT处理Annotation
  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
{
 String table();
}

修饰标识属性
import java.lang.annotation.*;

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface IdProperty
{
 String column();
 String type();
 String generator();
}


修饰普通成员变量的Annotation
import java.lang.annotation.*;
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Property
{
 String column();
 String type();
}


  定义了三个Annotation之后,下面我们提供一个简单的Java类文件,这个Java类文件使用了上面三个Annotation来修饰

@Persistent(table="persons_table")
public class Person
{
 @IdProperty(column="person_id",type="integer",generator="identity")
 private int id;
 @Property(column="person_name",type="string")
 private String name;
 @Property(column="person_age",type="integer")
 private int age;

 public Person()
 {
 }

 public Person(int id , String name , int age)
 {
  this.id = id;
  this.name = name;
  this.age = age;
 }

 public void setId(int id)
 {
  this.id = id;
 }
 public int getId()
 {
   return this.id;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 public String getName()
 {
   return this.name;
 }

 public void setAge(int age)
 {
  this.age = age;
 }
 public int getAge()
 {
   return this.age;
 }

}


  上面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 HibernateAnnotationProcessor implements AnnotationProcessor
{
 //Annotation处理器环境,是该处理器与APT交互的重要途径
 private AnnotationProcessorEnvironment env;
 //构造HibernateAnnotationProcessor对象时,获得处理器环境
 public HibernateAnnotationProcessor(AnnotationProcessorEnvironment env)
 {
  this.env = env;
 }
 //循环处理每个对象
 public void process()
 {
  //遍历每个class文件
  for (TypeDeclaration t : env.getSpecifiedTypeDeclarations())
  {
   //定义一个文件输出流,用于生成额外的文件
   FileOutputStream fos = null;
   //获取正在处理的类名
   String clazzName = t.getSimpleName();
   //获取类定义前的Persistent Annotation
   Persistent per = t.getAnnotation(Persistent.class);
   //当per Annotation不为空时才继续处理
   if(per != null)
   {
    try
    {
     //创建文件输出流
     fos = new FileOutputStream(clazzName + ".hbm.xml");
     PrintStream ps = new PrintStream(fos);
     //执行输出
     ps.println("<?xml version="1.0"?>");
     ps.println("<!DOCTYPE hibernate-mapping");
     ps.println(" PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"");
     ps.println("    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">");
     ps.println("<hibernate-mapping>");
     ps.print(" <class name="" + t);
     //输出per的table()的值
     ps.println("" table="" + per.table() + "">");
     for (FieldDeclaration f : t.getFields())
     {
      //获取指定FieldDeclaration前面的IdProperty Annotation
      IdProperty id = f.getAnnotation(IdProperty.class);
      //如果id Annotation不为空
      if (id != null)
      {
       //执行输出
       ps.println("  <id name=""
        + f.getSimpleName()
        + "" column="" + id.column()
        + "" type="" + id.type()
        + "">");
       ps.println("   <generator class=""
        + id.generator() + ""/>");
       ps.println("  </id>");
      }
      //获取指定FieldDeclaration前面的Property Annotation
      Property p = f.getAnnotation(Property.class);
      //如果p Annotation不为空
      if (p != null)
      {
       //执行输出
       ps.println("  <property name=""
        + f.getSimpleName()
        + "" column="" + p.column()
        + "" type="" + p.type()
        + ""/>");  
      }
     }
     ps.println(" </class>");
     ps.println("</hibernate-mapping>");
    }
    catch (Exception e)
    {
     e.printStackTrace();
    }
    finally
    {
     //关闭输出流
     try
     {
      if (fos != null)
      {
       fos.close();
      }
     }
     catch (IOException ex)
     {
      ex.printStackTrace();
     }
    }
   }
  }
 }
}


  上面的Annotation处理器比较简单,与前面通过反射来获取Annotation信息不同的是,这个Annotation处理器使用AnnotationProcessorEnvironment来获取Annotation信息,AnnotationProcessorEnvironment包含了一个getSpecifiedTypeDeclarations方法,可获取所有需要处理的类声明,这个类声明可包括类,接口,和枚举等声明,由TypeDeclaration对象表地示,与Classc对象的功能大致相似,区别只是TypeDeclaration是静态,只要有类文件就可以获得该对象,而Class是动态的,必须由虚拟机装载了指定类文件后才会产生。

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 HibernateAnnotationFactory implements AnnotationProcessorFactory
{
 //所有支持的注释类型
 public Collection<String> supportedAnnotationTypes()
 {
  return Arrays.asList("Property" , "IdProperty" , "Persistent");
 }
 //返回所有支持的选项
 public Collection<String> supportedOptions()
 {
  return Arrays.asList(new String[0]);
 }
 //返回Annotation处理器
 public AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> atds,AnnotationProcessorEnvironment env)
 {
  return new HibernateAnnotationProcessor(env);
 }  
}


  提供了上面的处理器工厂后,就可以使用APT工具来处理上面的Person.java源文件,并根据该源文件来生成一个XML文件。 APT工具位于JDK的安装路径的bin路径下。。

运行APT命令时,可以使用-factory选项来指定处理器工厂类
如下所示
rem 使用HibernateAnnotationFactory作为处理器工厂来处理Person.java中的Annotation
apt -factory HibernateAnnotationFactory Person.java

  

  使用APT工具,HibernateAnnotationFactory工厂来处理Person.java后,将可以看到在相同路径下,生成了一个Person.hbm.xml文件了,该文件内容如下
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
 PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="Person" table="persons_table">
  <id name="id" column="person_id" type="integer">
   <generator class="identity"/>
  </id>
  <property name="name" column="person_name" type="string"/>
  <property name="age" column="person_age" type="integer"/>
 </class>
</hibernate-mapping>

 



 

总结
   通过上面生成的xml文件,我们可以看出,通过使用APT工具确实可以简化程序开发,程序员只需把一些关键信息通过Annotation写在程序中,然后使用APT工具就可生在额外的文件。

 

转自:http://blog.sina.com.cn/heyitang

Files contained in apt-mirror-api-0.1.jar: META-INF/MANIFEST.MF META-INF/maven/com.moparisthebest.aptIn16/apt-mirror-api/pom.properties META-INF/maven/com.moparisthebest.aptIn16/apt-mirror-api/pom.xml com.sun.mirror.apt.AnnotationProcessor.class com.sun.mirror.apt.AnnotationProcessorEnvironment.class com.sun.mirror.apt.AnnotationProcessorFactory.class com.sun.mirror.apt.AnnotationProcessorListener.class com.sun.mirror.apt.AnnotationProcessors.class com.sun.mirror.apt.Filer.class com.sun.mirror.apt.Messager.class com.sun.mirror.apt.RoundCompleteEvent.class com.sun.mirror.apt.RoundCompleteListener.class com.sun.mirror.apt.RoundState.class com.sun.mirror.declaration.AnnotationMirror.class com.sun.mirror.declaration.AnnotationTypeDeclaration.class com.sun.mirror.declaration.AnnotationTypeElementDeclaration.class com.sun.mirror.declaration.AnnotationValue.class com.sun.mirror.declaration.ClassDeclaration.class com.sun.mirror.declaration.ConstructorDeclaration.class com.sun.mirror.declaration.Declaration.class com.sun.mirror.declaration.EnumConstantDeclaration.class com.sun.mirror.declaration.EnumDeclaration.class com.sun.mirror.declaration.ExecutableDeclaration.class com.sun.mirror.declaration.FieldDeclaration.class com.sun.mirror.declaration.InterfaceDeclaration.class com.sun.mirror.declaration.MemberDeclaration.class com.sun.mirror.declaration.MethodDeclaration.class com.sun.mirror.declaration.Modifier.class com.sun.mirror.declaration.PackageDeclaration.class com.sun.mirror.declaration.ParameterDeclaration.class com.sun.mirror.declaration.TypeDeclaration.class com.sun.mirror.declaration.TypeParameterDeclaration.class com.sun.mirror.type.AnnotationType.class com.sun.mirror.type.ArrayType.class com.sun.mirror.type.ClassType.class com.sun.mirror.type.DeclaredType.class com.sun.mirror.type.EnumType.class com.sun.mirror.type.InterfaceType.class com.sun.mirror.type.MirroredTypeException.class com.sun.mirror.type.MirroredTypesException.class com.sun.mirror.type.PrimitiveType.class com.sun.mirror.type.ReferenceType.class com.sun.mirror.type.TypeMirror.class com.sun.mirror.type.TypeVariable.class com.sun.mirror.type.VoidType.class com.sun.mirror.type.WildcardType.class com.sun.mirror.util.DeclarationFilter.class com.sun.mirror.util.DeclarationScanner.class com.sun.mirror.util.DeclarationVisitor.class com.sun.mirror.util.DeclarationVisitors.class com.sun.mirror.util.Declarations.class com.sun.mirror.util.SimpleDeclarationVisitor.class com.sun.mirror.util.SimpleTypeVisitor.class com.sun.mirror.util.SourceOrderDeclScanner.class com.sun.mirror.util.SourcePosition.class com.sun.mirror.util.TypeVisitor.class com.sun.mirror.util.Types.class
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值