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

news/2024/10/18 18:29:40/
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;}//循环处理每个对象@Overridepublic 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 {//返回此工厂或任何方法所识别的选项 它可能创建的处理器@Overridepublic Collection<String> supportedOptions() {return Collections.emptySet();}//返回此工厂支持的注释类型的名称。@Overridepublic Collection<String> supportedAnnotationTypes() {return Collections.singleton("annotations.ExtractInterface");}//返回注解处理器,该方法以包含类型声明的Set(使用apt工具时传入的Java类)以及AnnotationProcessorEnvironment对象为参数(将传入给处理器对象)//一旦返回的String集合中没有你的注解的完整类名。apt就会抱怨没有找到相应的处理器,从而发出警告信息,然后什么也不做就退出。//返回一组注释的注释处理器@Overridepublic AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> atds, AnnotationProcessorEnvironment env) {return new InterfaceExtractorProcessor(env);}
}

http://www.ppmy.cn/news/327585.html

相关文章

关于macbook只能登陆微信但无法打开网络的问题解决

遇到的问题&#xff1a; macbook在连接网络之后&#xff0c;只能登陆微信和邮箱等第三方应用软件&#xff0c;但是无法在浏览器中打开任何网页。尝试过&#xff1a;重启、更换网络连接方式、浏览器类型之后仍然无法解决。 网上找到的方法&#xff1a; 修改DNS&#xff08;http…

signal

读信号&#xff0c;dqs 是对齐到dq的边沿&#xff0c; 写信号&#xff0c;dqs 的边沿是对到中间的。 spec 就是这样规定的。我们在dq的最中间的采样&#xff0c;肯定是最安全的。 dqs 是对齐到dq的边沿 &#xff0c; 在silicon 内部&#xff0c;还是通过移位完成的。 rl: re…

草原风光

前几天出了趟差&#xff0c;在桑根达来转车的时候在附近拍了几张照片&#xff0c;把还过得去的拿出来秀一下 http://lvjack163.blog.163.com/album

卑微小测试的一天----自动生成正交法测试用例

前言 工作过程中&#xff0c;我们接触到需求后第一要务是 熟悉需求并且输出测试用例&#xff0c;针对接口测试的入参测试&#xff0c;需要校验大量入参的组合场景&#xff0c;这时我们通常采用正交法来设计测试用例&#xff0c;在减少测试用例的数量时&#xff0c;同时保障测试…

算法学习day17

110 平衡二叉树 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true…

Android三大按钮,模拟Android导航栏三大金刚按键点击

模拟Android导航栏三大金刚按键点击 这里需要使用的是AccessibilityService无障碍辅助服务&#xff0c;可以全局监听界面所有的变化&#xff1b; 1.构建无障碍服务 public class FloatService extends AccessibilityService { private static AccessibilityService service; pu…

变形金刚2 昨日上映 汽车人提前降临地球

万众瞩目耗资约13.6亿人民币的《变形金刚2》终于在昨天全球上映了&#xff0c;这部电影的上映不仅让全球影迷大呼过瘾&#xff0c;同时也令全球的车迷大饱眼福。随着一句“汽车人&#xff0c;变形出发”《变形金刚2》一定会引爆整个暑期档。 汽车人已经降临地球 明天汽车人就将…

推荐-最新GBA游戏下载,不用注册直接下载!(2)

2299 Castlevania Double Pack(U)下载地址 http://download.tts8.com/games/down_17642.htm 2297 Hi Hi Puffy AmiYumi Kaznapped(J)下载地址 http://download.tts8.com/games/down_17641.htm 2296 Ochainu no Bouken Jima(J)下载地址 http://download.tts8.com/games/down_131…