java annotation apt_JAVA APT处理Annotation

JAVA APT处理Annotation

使用APT处理Annotation

APT(Annotationprocessing 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;

// omit constructor and get ang setmethod....

}

上面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 HibernateAnnotationProcessorimplements AnnotationProcessor {

// Annotation处理器环境,是该处理器与APT交互的重要途径

private AnnotationProcessorEnvironment env;

// 构造HibernateAnnotationProcessor对象时,获得处理器环境

publicHibernateAnnotationProcessor(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("<?xmlversion =\"1.0\"?>");

ps.println(");

ps.println(" PUBLIC \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"");

ps.println(" \"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">");

ps.println("");

ps.print("

// 输出per的table()的值

ps.println("\"table=\"" + per.table() + "\">");

for (FieldDeclaration f : t.getFields()) {

// 获取指定FieldDeclaration前面的IdPropertyAnnotation

IdProperty id =f.getAnnotation(IdProperty.class);

// 如果id Annotation不为空

if (id != null) {

// 执行输出

ps.println(" ");

ps.println(" ");

ps.println(" ");

}

// 获取指定FieldDeclaration前面的PropertyAnnotation

Property p =f.getAnnotation(Property.class);

// 如果p Annotation不为空

if (p != null) {

// 执行输出

ps.println(" ");

}

}

ps.println(" ");

ps.println("");

} 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 HibernateAnnotationFactoryimplements AnnotationProcessorFactory {

//所有支持的注释类型

public CollectionsupportedAnnotationTypes() {

return Arrays.asList("Property" ,"IdProperty" , "Persistent");

}

//返回所有支持的选项

public CollectionsupportedOptions() {

return Arrays.asList(new String[0]);

}

//返回Annotation处理器

public AnnotationProcessorgetProcessorFor(Setatds,AnnotationProcessorEnvironment env) {

return newHibernateAnnotationProcessor(env);

}

}

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

运行APT命令时,可以使用-factory选项来指定处理器工厂类

如下所示 run.cmd

rem 使用HibernateAnnotationFactory作为处理器工厂来处理Person.java中的Annotation

apt -factory HibernateAnnotationFactoryPerson.java

使用APT工具,HibernateAnnotationFactory工厂来处理Person.java后,将可以看到在相同路径下,生成了一个Person.hbm.xml文件了,该文件内容如下

最后在磁盘上的目录格式如下图:

注:在运行上图中的run.cmd文件中,如果出现某些类没有编译成.class文件,则需要手功通过javacmyClass.java 进行编译,最后得到的Person.hbm.xml就是我们所要的文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值