- 新建两个 java lib 项目,分别放置 注解(工程名称为myAnnotation)和注解处理器(工程名称为 Compiler)和一个Android工程
注解
- 再工程 myAnnotation 新建注解
java 版本
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface One {}
Kotlin 版本
@Target(AnnotationTarget.CLASS)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
annotation class Two
如果是 kotlin 版本 需要 再 build.gradle 里面 增加 以下代码 来让工程支持 kotlin的语法
apply plugin: 'kotlin'
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
注解处理器
说在前面
- 注解处理器(compiler)工程main 的目录结构是kotlin还是 java 包 不影响最终结果
- 需要再main 底下新建package,名称为
resources - 再
resources底下新建文件META-INF/services/javax.annotation.processing.Processor - 再
javax.annotation.processing.Processor下写入 注解处理器的全名称 eg:com.example.annotationtwo.TwoProcessor
编写 注解处理器
- 如果需要支持kotlin 则 与
myannotation支持的方式相同,再build.gradle增加代码即可 - 因为注解处理器需要使用到 注解 所以需要再
build.gradle导入 刚才的注解库
implementation project(':myannotation')
- 编写处理器
@SupportedAnnotationTypes("com.example.annotationtwo.Two")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
class TwoProcessor2 : AbstractProcessor() {
var messager: Messager? = null
override fun init(processingEnv: ProcessingEnvironment) {
super.init(processingEnv)
messager = processingEnv.messager
messager?.printMessage(Diagnostic.Kind.WARNING, "newbie:init")
}
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
messager!!.printMessage(Diagnostic.Kind.WARNING, "TwoProcessor2 process")
return false
}
}
特别请注意,如果 printMessage的类型为Diagnostic.Kind.Error 则编译会直接报错,所以,这里只能采用WARNING或者 MANDATORY_WARNING 因为gradle版本的关系,据说有问题,本人 gradle 版本 ext.kotlin_version = '1.3.61' 不可以 使用其他 类型进行打印, Diagnostic.Kind.NOTE 是不会输出日志的
3. process 的返回值决定是否只在注解发生改变的时候重新编译,如果是true的话,则只在改变的时候重新编译。
4. SupportedAnnotationTypes源自于 父类 override fun getSupportedAnnotationTypes(): MutableSet<String> 表明该注解处理器可以支持解释哪些注解类,在 kotlin 里面可以直接写成注解处理器的注解即可@SupportedAnnotationTypes("com.example.annotationtwo.Two") 注意入参为 全名称,如果是多个则直接后面继续增加即可 @SupportedAnnotationTypes("","")
5. SupportedSourceVersion 也是源自父类 override fun getSupportedSourceVersion(): SourceVersion 表明支持的jdk的版本 如果低于8 的版本会报 警告 来自注释处理程序 'org.jetbrains.kotlin.kapt3.base.ProcessorWrapper' 的受支持 source 版本 'RELEASE_7' 低于 -source '1.8'
6. 如果需要携带参数给到 注解处理器,则 需要重写 override fun getSupportedOptions(): MutableSet<String>
// 设置支持的指令
override fun getSupportedOptions(): MutableSet<String> = hashSetOf("myoption")
override fun init(processingEnv: ProcessingEnvironment) {
super.init(processingEnv)
messager = processingEnv.messager
// 取出这个值
val myoption = processingEnv.options["myoption"]
messager?.printMessage(Diagnostic.Kind.WARNING, "newbie:$myoption")
}
参数的传入处,就在 自己的android项目(上面是java lib项目)的build.gradle 中(下面会说)
7. 如果注解处理器包含中文注释,则需要再 build.gradle 中新增
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
使用注解处理器
- 新建Android工程
- Android工程项目 的build.gradle 中 可以根据自己工程语言的采用(
kotlin还是java)来选择不同的导入方式(kapt还是annotationProcessor) 如果是kapt 请注意需要导入apply plugin: 'kotlin-kapt'annotationProcessor再gradle 2.2.0之后就自带了,所以不需要导入任何的插件即可使用
apply plugin: 'kotlin-kapt'
dependencies {
kapt project(":Compiler")
implementation project(':myannotation')
}
或者 java 版版本
dependencies {
annotationProcessor project(":Compiler")
implementation project(':myannotation')
}
- 如果需要传递数据给到注解处理器
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
argument "myoption", "value1"
argument "key2", "value2"
}
}
}
}
注意事项
- 错误 :
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:kaptDebugKotlin'
可能的原因之一: 再使用了kotlin的项目里面导入了kotlin-kapt的插件,还是用
annotationProcessor应该改为kapt即可可能的原因之二: 再
implementation的工程中,有 注解处理器的存在, 应该 : 将注解和注解处理器分成两个不同的java lib库,kapt导入 注解处理器的lib ,注解的库 使用implemention进行导入可能的原因之三:再注解处理器 的库里面打印日志使用的是
ERROR,如果采用Error,会抛异常, 跟throw exception("message")是一个道理 ,kapt支支持两种方式的打印Diagnostic.Kind.MANDATORY_WARNING和Diagnostic.Kind.WARNING