自定义Java编译时注解处理器

自定义Java编译时注解处理器
1. 絮絮叨叨
 
要么是注解跟我有仇,要么是公司配发的笔记本跟我有仇,要么是因为心急吃不了热豆腐
 
痛定思痛:从头开始,新建一个Java项目,实现一个超级简单的注解@Hello
 
通过获取被标识类的类名(原类),创建对应的Hello类;Hello类中,有一个sayHello()方法,可以打印原类的类名
 
在此,记录一下如何定义一个简单的Java编译时注解处理器
 
PS:附上之前的注解学习文档 —— 1. Java注解
 
1.1 AbstractProcessor
 
自定义Java编译时注解处理器,一般都是通过继承AbstractProcessor实现的
 
AbstractProcessor类实现了Processor接口,为自定义注解处理器提供了便利
 
一般的话,只需要重写process() 方法即可,其他方法按需重写
 
public synchronized void init(ProcessingEnvironment processingEnv) 
 
public Set<String> getSupportedAnnotationTypes()
 
public SourceVersion getSupportedSourceVersion() 
 
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) 
 
init()方法
 
注解处理器都使用默认构造函数(入参和方法体都为空)进行创建,init() 方法以在注解处理器创建好后执行一些初始化工作
 
ProcessingEnvironment是JDK为注解处理器提供的注解处理的工具框架
 
通过processingEnv,可以获取注解处理中经常使用到的、有用的工具类实例,如Messager、Filer、Elements等
 
getSupportedAnnotationTypes()方法
 
在该方法中,可以指定注解处理器支持的注解,准确地说是注解的Name,如MyAnnotion.class.getCanonicalName()
 
AbstractProcessor的默认实现:获取类头部@SupportedAnnotationTypes注解的value,其value是一个String[];如果是没有使用@SupportedAnnotationTypes,则返回一个空的set
 
总结: 注解处理器支持的注解,要么在方法体里面指定,要么通过@SupportedAnnotationTypes指定
 
getSupportedSourceVersion()方法
 
在该方法中,可以指定Java源代码的版本(source version)
 
AbstractProcessor的默认实现:获取类头部@SupportedSourceVersion注解的value,其value是一个枚举类SourceVersion;如果是没有使用@SupportedSourceVersion,则返回SourceVersion.RELEASE_6
 
总结: 注解处理器支持的sourceVersion,要么该方法体中指定,要么通过@SupportedSourceVersion指定
 
process()方法(重头戏)
 
相当于注解注解器的main方法,实现对被已注册的注解标注的element(方法、类、接口等)的处理
 
process方法对注解的处理不是一次到位的,可能存在多个round
 
每次都是处理上一轮的element上标注的注解,并返回这些注解是否已经被注解处理器声明
 
如果返回true,后续的注解处理器将不会处理这些注解
 
对process()方法中声明的理解
 
之所以叫编译时注解处理器,是因为源代码被compiler编译成字节码前,会先扫描源代码中的注解
 
如果注解有对应的注解处理器,则会调用process() 方法处理被注解标注的element
 
这个处理过程可能会产生新的源代码、甚至修改已有的源代码,因此需要进行多轮的注解处理
 
自己的理解待验证,后续有空会做验证的

推荐阅读