0%

注解 in kotlin

注解

定义在类、方法、字段 、参数前的”注释“。注解(annotation)可以被编译器打包进class文件。

元注解

有一些注解可以修饰其他注解,这些注解就称为元注解(meta annotation)。常用 元注解有@Retention、@ Target、@ Repeatable、@ MustBeDocumented

  • @Target 指定可以用该注解标注的元素的可能的类型(类、函数、属性、表达式等);
  • @Retention 指定该注解是否存储在编译后的 class 文件中,以及它在运行时能否通过反射可见 (默认都是 true);
  • @Repeatable 允许在单个元素上多次使用相同的该注解;
  • @MustBeDocumented 指定该注解是公有 API 的一部分,并且应该包含在生成的 API 文档中显示的类或方法的签名中。
1
2
3
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Subscribe(val threadMode: ThreadMode = ThreadMode.POSTING)
运行时注解

运行时注解@Retention(AnnotationRetention.RUNTIME),大多数时候是在运行时使用反射来实现所需效果。

Java提供的使用反射API读取Annotation的方法包括:

判断某个注解是否存在于ClassFieldMethodConstructor

  • X.isAnnotationPresent(Class)

使用反射API读取Annotation:

  • X.getAnnotation(Class)
    例如:
1
2
3
4
5
6
7
8
val methods = clazz.javaClass.declaredMethods
for (method in methods) {
// 获取注解
val annotation = method.getAnnotation(Subscribe::class.java)
if (annotation != null) {
invoke(annotation, method, clazz, msg)
}
}
编译时注解

注解处理器(annotation processor)是javac的一个工具,它用来在编译时扫描和处理注解。你可以对自定义注解,并注册相应的注解处理器,用于处理你的注解逻辑。

创建java or kotlin Library, 实现一个自定义注解处理器(AbstractProcessor),至少重写四个方法,并且注册你的自定义Processor。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
override fun init(processingEnv: ProcessingEnvironment) {
super.init(processingEnv)
//element代表程序的元素,例如包、类、方法。
elementUtils = processingEnv.elementUtils
}

override fun getSupportedAnnotationTypes(): MutableSet<String> {
val types = LinkedHashSet<String>()
types.add(Subscribe::class.java.canonicalName)
return types
}

override fun getSupportedSourceVersion(): SourceVersion {
return SourceVersion.latestSupported()
}

override fun process(
annotations: MutableSet<out TypeElement>,
roundEnv: RoundEnvironment
): Boolean {
// 处理注解
}
注册Processor

AbstractProcessor实现之后不能直接使用,需要注册之后才能运行,有两种方式:

  1. 手动注册

在实现AbstractProcessor的项目中添加resources/META-INF文件夹,并在META-INF下添加一个名称为javax.annotation.processing.Processor的文本文件,在里面写入实现AbstractProcessor类的全名vip.lovek.processor.EventBusProcessor

  1. 自动注册

使用google提供的AutoService主动注册。在AbstractProcessor实现类上加上注解:

1
2
3
4
5
@AutoService(Processor::class)
class EventBusProcessor : AbstractProcessor() {}

// 导入依赖库
kapt 'com.google.auto.service:auto-service:1.0-rc7' // kotlin

自动注册方式在kotlin中有bug,如果不能自动生成,推荐手动注册。

生成代码

AbstractProcessor中提供了生成代码的辅助类:Filer。 在ProcessingEnvironment中,生成代码就是一个创建文件写入文本内容的过程。生成kotlin源码有很名的kotlinpoet框架。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private fun createFile() {
val typeSpec = TypeSpec.classBuilder("HelloWorld")
.addFunction(
FunSpec.builder("hello").addStatement("println(%P)", "hello world").build()
)
.build()
val mainFunction = FunSpec.builder("main")
.addCode(
"""
|var total = 0
|for (i in 0 until 10) {
| total += i
|}
|""".trimMargin()
)
.build()
val file = FileSpec.builder("vip.lovek.sharingan", "HelloWorld")
.addType(typeSpec)
.addFunction(mainFunction)
.build()
try {
file.writeTo(processingEnv.filer)
} catch (e: Exception) {
}
}

生成代码内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package vip.lovek.sharingan

class HelloWorld {
fun hello() {
println("""hello world""")
}
}

fun main() {
var total = 0
for (i in 0 until 10) {
total += i
}
}
赞赏是最好的支持