使用apt处理注解-将观察者模式用于apt

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * * 使用apt处理注解
 *  *  注解处理工具apt,这是Sun为了帮助注解的处理过程而提供的工具。由于这是该工具的第一版,其功能还比较基础,不过它确实有助于程序员的开发工作。
 *  *  与javac一样,apt被设计为操作java源文件,而不是编译后的类。默认情况下,apt会在处理完源文件后编译他们。如果在系统构建的过程中会自动创建
 *  *  一些新的源文件,那么这个特性非常有用。事实上,apt会检查新生成的源文件中注解,然后将所有文件一同编译。
 *  *  当注解处理器生成一个新的源文件时,该文件会在新一轮的注解处理中接受检查。该工具会一轮一轮地处理,直到不再有新的源文件产生为止。然后它再编译
 *  *  所有的源文件。
 *  *  程序员自定义的每一个注解都需要自己的处理,而apt工具能够很容易地将多个注解处理器组合在一起。有了它,程序员就可以指定多个要处理的类,这比程序员
 *  *  自己遍历所有的类文件简单多了,此外还可以添加监听器,并在一轮注解处理过程结束的时候收到通知消息。
 *  *
 *  *  在撰写本章的时候,apt还不是一个正式的Ant任务,不过显示可以将其作为一个Ant的外部任务运行。要想编译这一节中出现的注解处理器,你必须将tools.jar
 *  *  设置在你的classpath中,这个工具类库同时还包含了com.sun.mirror.*接口。
 *  *  通过使用AnnotationProcessorFactory,apt能够为每一个它发现的注解生成一个正确的注解处理器。当你使用apt的时候,必须指明一个工厂类,或者指明
 *  *  能找到apt所需的工厂类的路径。否则,apt会踏上一个神秘的探索之旅,详细的信息可以再Sun文档“开发一个注解处理器”一节中找到。
 *  *  使用apt生成注解处理器时,我们无法利用java的反射机制,因为我们操作时源代码,而不是编译后的类。使用mirrorAPI能够解决这个问题,它使我们能够在未经
 *  *  编译源代码中查看方法,域以及类型。
 */

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface ExtractInterface {
    public String value();
}
/**
 * RetentionPolicy 是SOURCE 因为当我们从一个使用了该注解的类中抽取出接口之后
 * 没有必要再保留这些注解信息。
 * 在Multiplier类中(它只对正整数起作用)有一个multiplay方法,该方法多次调用一个私有方法以实现乘法操作,add方法
 * 不是公共的,因此不将其作为接口的一部分,注解给处理值为IMultiplier,这是将要生成接口的名字
 */
@ExtractInterface("IMultiplier")
public class Multiplier {
    public int multiplay(int x ,int y) {
        int total = 0;
        for (int i = 0; i < x ; i++) {
            total = add(total,y);
        }
        return total;
    }

    private int add(int x,int y) {
        return x + y;
    }

    public static void main(String[] args) {
        Multiplier multiplier = new Multiplier();
        System.out.println("11*16 = " +multiplier.multiplay(11,16));
    }
}
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.Modifier;
import com.sun.mirror.declaration.ParameterDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

/**
 * 所有的工作都在process()方法中完成,在分析一个类的时候,我们用MethodDeclaration类以及其上的getModifiers()方法中来找到public
 * 方法(不包含static的那些)。一旦找到我们所需的public方法,就将其保存在一个ArrayList中,然后在一个.java文件中,创建新的接口的方法定义。
 * 注意,处理器类构造器以AnnotationProcessorEnvironment对象参数。通过该对象,我们就能知道apt正在处理的所有类型(类定义),并可以通过它
 * 获取Message对象和Filer对象。Messager对象可以用来向用户报告信息,比如处理过程中发生的任何错误,以及错误在源代码中出现的位置等。Filer是
 * 一种PrintWriter,我们可以通过它创建新的文件。不使用普通的PrintWriter而使用Filer对象的主要原因是,只有这样apt才能知道我们创建的新文件,
 * 从而对新文件进行注解处理,并且在需要的时候编译他们
 * 同时我们看到片,Filer的createSourceFile()方法以将新建新的类或接口的名字,打开了一个普通的输出流,现在还没有什么工具帮助程序员创建java
 * 语言结果,所以我们只能用基本的print和println方法来生成java源代码,因此,你必须小心仔细地处理括号,确保其闭合,并且确保生成的代码语法正确
 */
public class InterfaceExtractorProcessor implements AnnotationProcessor { //AnnotationProcessor 注解处理器
    /**
     * 使用APT工具来处理源文件时,APT首先检测在源代码文件中包含哪些Annotation,然后APT将查找所需的处理器工厂,
     * 并由工厂来返回相应的Annotation处理器。如果该处理器工厂支持这些Annotaion,处理器工厂返回的Annotaion处理器将会处理这些Annotation,
     * 如果生成的源文件中再次包含Annotaion,APT将会重复上面过程,直至没有新文件生成。
     */

    private final AnnotationProcessorEnvironment annotationProcessorEnvironment; //AnnotationProcessorEnvironment是APT工具与注释环境通信的途径

    private ArrayList<MethodDeclaration> interfaceMethods = new ArrayList<MethodDeclaration>(); //Represents a method of a class or interface.方法声明


    //获取处理器环境
    public InterfaceExtractorProcessor(AnnotationProcessorEnvironment annotationProcessorEnvironment) {
        this.annotationProcessorEnvironment = annotationProcessorEnvironment;
    }

    //循环处理每个对象
    @Override
    public void process() {
        //查询注解处理器环境中的类型声明
        for (TypeDeclaration specifiedTypeDeclaration : annotationProcessorEnvironment.getSpecifiedTypeDeclarations()) {
            ExtractInterface annotation = specifiedTypeDeclaration.getAnnotation(ExtractInterface.class); //获取注解
            if (annotation == null) {
                break;
            }
            for (MethodDeclaration method : specifiedTypeDeclaration.getMethods()) { //getMethods 获取所有方法
                if (method.getModifiers().contains(Modifier.PUBLIC) && !(method.getModifiers().contains(Modifier.STATIC))) { //getModifiers 获取修饰符 contains 是否包含
                    interfaceMethods.add(method);
                }
            }

            if (interfaceMethods.size() > 0) {
                try {
                    PrintWriter sourceFile = annotationProcessorEnvironment.getFiler().createSourceFile(annotation.value());//创建文件
                    sourceFile.println("package"+specifiedTypeDeclaration.getPackage().getQualifiedName()+";"); //返回包完全限制名
                    sourceFile.println("public interface"+annotation.value()+" {");
                    for (MethodDeclaration interfaceMethod : interfaceMethods) {
                        sourceFile.println(" public");
                        sourceFile.println(interfaceMethod.getReturnType() +" "); //得到此参数的返回类型
                        sourceFile.println(interfaceMethod.getSimpleName()+" ("); //返回此方法简单名称
                        int i = 0;
                        for (ParameterDeclaration parameter : interfaceMethod.getParameters()) { //返回此方法或构造函数的形式参数 参数声明
                            sourceFile.print(parameter.getType() + " " + parameter.getSimpleName());
                            if (++i < interfaceMethod.getParameters().size()) {
                                sourceFile.print(",");
                            }
                        }
                        sourceFile.println(")");
                    }
                    sourceFile.println("}");
                    sourceFile.close();
                }catch (IOException ioException) {
                    throw new RuntimeException(ioException);
                }

            }
        }
    }
}
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.AnnotationProcessorFactory;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;

/**
 * AnnotationProcessorFactory接口只有三个方法,
 */
public class InterfaceExtractorProcessorFactory implements AnnotationProcessorFactory {
    //返回此工厂或任何方法所识别的选项 它可能创建的处理器
    @Override
    public Collection<String> supportedOptions() {
        return Collections.emptySet();
    }

    //返回此工厂支持的注释类型的名称。
    @Override
    public Collection<String> supportedAnnotationTypes() {
        return Collections.singleton("annotations.ExtractInterface");
    }

    //返回注解处理器,该方法以包含类型声明的Set(使用apt工具时传入的Java类)以及AnnotationProcessorEnvironment对象为参数(将传入给处理器对象)
    //一旦返回的String集合中没有你的注解的完整类名。apt就会抱怨没有找到相应的处理器,从而发出警告信息,然后什么也不做就退出。
    //返回一组注释的注释处理器
    @Override
    public AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> atds, AnnotationProcessorEnvironment env) {
        return new InterfaceExtractorProcessor(env);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值