## 0x01 继承AbstractProcessor抽象类

当定义好Annotation注解后,接下来就需要一个注解处理器来处理我们的自定义注解了。实现Java Annotation一般需要继承AbstractProcessor抽象类,并且重写其四个方法来实现提取,解析并处理自定义注解的逻辑如下:

class WondertwoProcessor extends AbstractProcessor {//返回注解处理器可处理的注解操作@Overridepublic Set<String> getSupportedOptions() {return super.getSupportedOptions();}//得到注解处理器可以支持的注解类型@Overridepublic Set<String> getSupportedAnnotationTypes() {return super.getSupportedAnnotationTypes();}//执行一些初始化逻辑@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);}//核心方法,扫描,解析并处理自定义注解,生成***.java文件@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {return false;}
}

## 0x02 重写核心方法process()

由上可知process()方法才是扫描,解析,处理注解的核心方法,动手实战一下写一个简单的WondertwoProcessor来提取自定义注解@CustomizeInterface,然后借助JavaPoet生成Java接口文件。

/*** 自定义注解处理器,将类中public方法提取为接口方法(不含static方法)* {*     Exec: apt -factory annotation3.WondertwoFactory*     ProvinceDefiner.java -s ../annotaion3* }* Created by wondertwo on 2016/10/18.*/
class WondertwoProcessor extends AbstractProcessor {private ProcessingEnvironment envir;public WondertwoProcessor(ProcessingEnvironment env) {this.envir = env;}@Overridepublic Set<String> getSupportedOptions() {return super.getSupportedOptions();}@Overridepublic Set<String> getSupportedAnnotationTypes() {return super.getSupportedAnnotationTypes();}@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);}@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {for (TypeElement typeEle : annotations) {WondertwoInterface wondertwoInterface = typeEle.getAnnotation(WondertwoInterface.class);if (wondertwoInterface == null) break;Class clazz = typeEle.getClass();if (clazz.getDeclaredMethods().length > 0) {try {if (typeEle.getModifiers().contains(Modifier.PUBLIC)&& !typeEle.getModifiers().contains(Modifier.STATIC)) {PrintWriter writer = (PrintWriter) envir.getFiler().createSourceFile(wondertwoInterface.value());writer.println("package " + clazz.getPackage().getName() + ";");writer.println("public interface " + wondertwoInterface.value() + " {");for (Method method : clazz.getDeclaredMethods()) {writer.print("    public ");writer.print(method.getReturnType() + " ");writer.print(method.getName() + " (");int i = 0;for (TypeParameterElement parameter : typeEle.getTypeParameters()) {writer.print(parameter.asType() + " " + parameter.getSimpleName());if (++i < typeEle.getTypeParameters().size())writer.print(", ");}writer.println(");");}writer.println("}");writer.close();}} catch (IOException e) {throw new RuntimeException(e);}}}return true;}
}

看过《Java编程思想》的同学肯定对上面的实例非常眼熟,书中对应的实例也是提取非静态公有方法生成接口源文件,但由于是JDK6.0标准已经有很多API发生了很大的变化,本例基于JDK8!

可以看到我们只在process()方法中加入了处理注解,生成.java文件的逻辑,这里是的逻辑是根据自定义注解提取对应类的非静态public方法,然后将抽取的非静态共有方法拼接成对应的接口!

## 0x03 实例探究:Android依赖注解库ButterKnife

不会偷懒的程序员不是一个好程序员,Android开发者对ButterKnife依赖注解库一定耳熟能详,当我们UI布局中控件很多的时候ButterKnife无疑显著提高了开发效率。

作为一个注解库其实现的原理依然是Java Annotation的方式,我们在Github翻出ButterKnife源码文件,找到其核心类——注解处理类ButterKnifeProcessor.java,源码较长删减后如下:

public final class ButterKnifeProcessor extends AbstractProcessor {@Override public synchronized void init(ProcessingEnvironment env) {super.init(env);elementUtils = env.getElementUtils();typeUtils = env.getTypeUtils();filer = env.getFiler();}@Override public Set<String> getSupportedAnnotationTypes() {Set<String> types = new LinkedHashSet<String>();types.add(Bind.class.getCanonicalName());for (Class<? extends Annotation> listener : LISTENERS) {types.add(listener.getCanonicalName());}types.add(BindBool.class.getCanonicalName());types.add(BindColor.class.getCanonicalName());types.add(BindDimen.class.getCanonicalName());types.add(BindDrawable.class.getCanonicalName());types.add(BindInt.class.getCanonicalName());types.add(BindString.class.getCanonicalName());return types;}@Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {Map<TypeElement, BindingClass> targetClassMap = findAndParseTargets(env);for (Map.Entry<TypeElement, BindingClass> entry : targetClassMap.entrySet()) {TypeElement typeElement = entry.getKey();BindingClass bindingClass = entry.getValue();try {JavaFileObject jfo = filer.createSourceFile(bindingClass.getFqcn(), typeElement);Writer writer = jfo.openWriter();writer.write(bindingClass.brewJava());writer.flush();writer.close();} catch (IOException e) {error(typeElement, "Unable to write view binder for type %s: %s", typeElement,e.getMessage());}}return true;}@Override public Set<String> getSupportedOptions() {return Collections.singleton(OPTION_SDK_INT);}
}

如果想要进一步了解ButteKnife扫描,解析,处理注解,生成Java代码的每一部细节,可以参考文章:浅析ButterKnife

转载于:https://www.cnblogs.com/wondertwo/p/6017403.html

注解提高篇:自定义注解处理器(APT)相关推荐

  1. 深入JAVA注解(Annotation):自定义注解

    一.基础知识:元注解 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解 ...

  2. java注解教程 pdf_Java注解教程和自定义注解

    Java注解提供关于代码的信息,并且对它们注解的代码没有直接的影响.在这篇教程中,我们将学习Java注解,如何自定义注解,注解用法和如何使用反射解析注解. Java注解在Java1.5被引用并且在一些 ...

  3. java注解 源码_详解Java注解教程及自定义注解

    详解Java注解教程及自定义注解 更新时间:2016-02-26 11:47:06   作者:佚名   我要评论(0) Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个 ...

  4. Java提高篇 ——Java注解

    目录 一.注解 注解的定义 注解的应用 元注解 @Retention @Documented @Target @Inherited @Repeatable 注解的属性 Java 预置的注解 @Depr ...

  5. 深入理解Java注解Annotation及自定义注解

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解其他注解.Java5. ...

  6. java 自定义注解 解析_java自定义注解

    1.Annotation的工作原理: JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型.该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的c ...

  7. @valid注解_springboot使用自定义注解对接口参数校验

    目的: 对自定义注解有更好的认识,让参数校验变得更加简洁.灵活.方便. 正文: 首先,在pom文件引入hibernate的校验依赖 1.自定注解:(注意要加@Constraint约束) @Target ...

  8. java自定义注解解析及自定义注解

    jdk1.5之后提供了注解(Annotation)这一种语法.其主要作用是编译检查(比如@override)和代码分析(通过代码中添加注解,利用注解解析器对添加了注解的代码进行分析,获取想要的结果,一 ...

  9. java 自定义注解获取_Java自定义注解

    Java在1.5开始引入了注解,目前流行的框架都在用注解,可想而知注解的强大之处. 以下通过自定义注解来深入了解java注解. 一.创建自定义注解 package com.sam.annotation ...

最新文章

  1. Confluence 6 导入 SSL 证书和问题解决
  2. 用户控件制作时设计模式加载报错的解决办法
  3. vue项目部署到nginx
  4. 怎么用计算机计算出选手最后得分,WPS技巧:TRIMMEAN函数计算选手得分
  5. mysql计算用户平均下单周期
  6. 2048游戏代码python_200 行代码实现简易版 2048 游戏 (python)
  7. Leetcode每日一题:189.rotate-array(旋转数组)
  8. python多进程编程实例_Python多进程并发(multiprocessing)用法实例详解
  9. 记XMPP即时通讯协议的认识
  10. NAND Flash批量数据烧录
  11. 多路测温系统C51语言,基于单片机的多路温度检测系统的.docx
  12. 人工神经网络—神经元的数学模型
  13. java九宫格案例讲解_Java实现九宫格的教程详解
  14. linux ftp上传目录,Linux中ftp不能上传文件/目录的解决办法
  15. 在某软国际的那些日子
  16. 微信小助手 for mac(WeChatPlugin)使用攻略
  17. 联想计算机不能进入系统桌面,联想电脑无法重装系统-联想电脑怎么重装系统我的电脑启动后到不了桌面,最后屏幕上没有任何 爱问知识人...
  18. matlab包络分析函数,数据包络分析 (MATLAB代码).doc
  19. 日常bug记录——mybatis传值为null
  20. 连续两次入围Gartner魔力象限的Quick BI到底有何魔力?

热门文章

  1. git如何添加远程主机_git 配置远程主机名
  2. docker build命令详解_『中级篇』docker之java容器运行外置springboot-jar(番外篇)(79)...
  3. oracle照片字节大小值,Oracle每条记录的平均字节数
  4. python书籍_Python 之父宣布加盟微软!包邮送几本 Python 书籍压压惊!
  5. linux docker安装mysql_Linux-docker安装mysql
  6. bootstrap 横铺 行_Bootstrap 排版
  7. linux ubuntu基础,linux基础入门详细分析(基于ubuntu)
  8. python graph_python graph什么意思
  9. Linux发布环境,linux发布环境初始化脚本
  10. 数据结构排序算法实验报告_数据结构与算法-堆排序