Java Annotation 高级应用<3>

三、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:
package com.bjinfotech.practice.annotation.apt;

/**
 * 定义Review Annotation
 * @author cleverpig
 *
 */
public @interface Review {
        public static enum TypeEnum{EXCELLENT,NICE,NORMAL,BAD};
        TypeEnum type();
        String name() default "Review";
}


C.ReviewProcessorFactory类:
清单8:
package com.bjinfotech.practice.annotation.apt;

import java.util.Collection;
import java.util.Set;
import java.util.Arrays;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
//请注意为了方便,使用了静态import
import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.emptySet;

/**
 * 生成ReviewProcessor的工厂类
 * @author cleverpig
 *
 */
public class ReviewProcessorFactory implements AnnotationProcessorFactory{
        /**
         * 获得针对某个(些)类型声明定义的Processor
         * @param atds 类型声明集合
         * @param env processor环境
         */
        public AnnotationProcessor getProcessorFor(
                        Set<AnnotationTypeDeclaration> atds, 
                        AnnotationProcessorEnvironment env){
                return new ReviewProcessor(env);
        }
        /**
         * 定义processor所支持的annotation类型
         * @return processor所支持的annotation类型的集合
         */
        public Collection<String>         supportedAnnotationTypes(){
                //“*”表示支持所有的annotation类型
                //当然也可以修改为“foo.bar.*”、“foo.bar.Baz”,来对所支持的类型进行修饰
            return unmodifiableCollection(Arrays.asList("*"));
    }
        
        /**
         * 定义processor支持的选项
         * @return processor支持选项的集合
         */
        public Collection<String>         supportedOptions(){
                //返回空集合
            return emptySet();
    }
        
        public static void main(String[] argv){
                System.out.println("ok");
        }
}


D.ReviewProcessor类:
清单9:
package com.bjinfotech.practice.annotation.apt;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.util.DeclarationVisitors;
import com.sun.mirror.util.DeclarationVisitor;

/**
* 定义Review annotation的Processor
* @author cleverpig
*
*/
public class ReviewProcessor implements AnnotationProcessor{
        //Processor所工作的环境
        AnnotationProcessorEnvironment env=null;
        
        /**
         * 构造方法
         * @param env 传入processor环境
         */
        public ReviewProcessor(AnnotationProcessorEnvironment env){
                this.env=env;
        }
        
        /**
         * 处理方法:查询processor环境中的类型声明,
         */
        public void process(){
                //查询processor环境中的类型声明
                for(TypeDeclaration type:env.getSpecifiedTypeDeclarations()){
                        //返回对类进行扫描、访问其声明时使用的DeclarationVisitor,
                        //传入参数:new ReviewDeclarationVisitor(),为扫描开始前进行的对类声明的处理
                        //        DeclarationVisitors.NO_OP,表示在扫描完成时进行的对类声明不做任何处理
                        DeclarationVisitor visitor=DeclarationVisitors.getDeclarationScanner(
                                        new ReviewDeclarationVisitor(),DeclarationVisitors.NO_OP);
                        //应用DeclarationVisitor到类型
                        type.accept(visitor);
                }
        }
}


E.ReviewDeclarationVisitor类:
清单10:
package com.bjinfotech.practice.annotation.apt;

import com.sun.mirror.util.*;
import com.sun.mirror.declaration.*;

/**
* 定义Review annotation声明访问者
* @author cleverpig
*
*/
public class ReviewDeclarationVisitor extends SimpleDeclarationVisitor{
        /**
         * 定义访问类声明的方法:打印类声明的全名
         * @param cd 类声明对象
         */
        public void visitClassDeclaration(ClassDeclaration cd){
                System.out.println("获取Class声明:"+cd.getQualifiedName());
        }
        
        public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration atd){
                System.out.println("获取Annotation类型声明:"+atd.getSimpleName());
        }
        
        public void visitAnnotationTypeElementDeclaration(AnnotationTypeElementDeclaration aed){
                System.out.println("获取Annotation类型元素声明:"+aed.getSimpleName());
        }
}


F.runapt.bat文件内容如下:
清单11:
E:
rem 项目根目录
set PROJECT_ROOT=E:\eclipse3.1RC3\workspace\tigerFeaturePractice
rem 包目录路径
set PACKAGEPATH=com\bjinfotech\practice\annotation\apt
rem 运行根路径
set RUN_ROOT=%PROJECT_ROOT%\build
rem 源文件所在目录路径
set SRC_ROOT=%PROJECT_ROOT%\test
rem 设置Classpath
set CLASSPATH=.;%JAVA_HOME%;%JAVA_HOME%/lib/tools.jar;%RUN_ROOT%

cd %SRC_ROOT%\%PACKAGEPATH%
apt -nocompile -factory com.bjinfotech.practice.annotation.apt.ReviewProcessorFactory  ./*.java
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值