Kotlin的注解和java的基本一致, 具体的细节可以看官方文档
https://kotlinlang.org/docs/reference/annotations.html
比较大的区别是Kotlin不支持@Inherited元注解,虽然一般情况下从父类使用注解的情况是非常少的。但总有人会碰到这样的问题。已经有人提出这个问题了,详见:https://youtrack.jetbrains.com/issue/KT-22265
注解的使用
注解一般用来在编译时处理代码,例如编译时进行格式检查,生成文档等
Kotlin的注解和Java的注解使用方式基本一致。获取注解相关信息的方式也基本一致
都需要实现AbstractProcessor来获取带指定的注解的元素的信息
public class AProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment env){ }
@Override
public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }
@Override
public Set<String> getSupportedAnnotationTypes() { }
@Override
public SourceVersion getSupportedSourceVersion() { }
}
- init Processor初始化的时候会调用此方法, ProcessingEnvironment是Processor所处的环境. ProcessingEnvironment有一个Options字段,用来存放一些特定的选项,例如可以从gradle插件中传递Project的一些信息进来.
android.defaultConfig.javaCompileOptions.annotationProcessorOptions.argument(“moduleName”, project.name)
-
process 是处理注解的主要方法,annoations中包含注解和使用注解的元素的信息,RoundEnvironment包含当前注解环境的上下文信息。return true表示该注解已处理完成,不再需要其他Processor处理
-
getSupportedAnnotationTypes 告诉Processor要扫面那些注解,返回的是包含指定注解类名的set
-
getSupportedSourceVersion 指定支持的version, 不同的Version支持的内容不一样,
1.1: nested classes
1.2: strictfp
1.3: no changes
1.4: assert
1.5: annotations, generics, autoboxing, var-args...
1.6: no changes
1.7: diamond syntax, try-with-resources, etc.
1.8: lambda expressions and default methods
一般传入SourceVersion.latest()即可
获取注解的信息
在process方法中可以获取到指定注解的信息。annoations 中的对象是TypeElement, TypeElement 是Element的子类,里面包含着注解的信息.
通过roundEnvironment.getElementsAnnotatedWith(注解类的Class)来获取当前注解的信息
Element的关键属性:
- name: 使用注解的元素的名称。如果是CLASS就是类全名,如果是方法就是方法名,其他类推
- getKind(): 使用注解的元素类型,如CLASS, PACKAGE, INTERFACE,FIELD等,对应注解的Target
- getModifiers(): 使用注解的元素的修饰符,如class的private, static, final等
- TypeMirror:对应Java 编程语言中的类型。 如ArrayType,DeclaredType,NullType等。主要用来判断使用者和注解参数的类型,通过typeMirror可以获取注解中Class参数的类名
注册Processor
AbstractProcessor实现之后不能直接使用,需要注册之后才能运行,有两种方式:
- 手动注册
在实现AbstractProcessor的项目中添加resources/META-INF文件夹,并在META-INF下添加一个名称为javax.annotation.processing.Processor的文本文件,在里面写入实现AbstractProcessor类的全名
- 自动注册
使用google提供的AutoService主动注册。在AbstractProcessor实现类上加上注解:
@AutoService(Processor::class)
就可以了。
AutoService也是通过注解的形式自动生成对应的文件和文件夹。
打印日志
由于AbstractProcessor的执行在编译器,所以不能直接使用android和java的日志输出方式,需要使用
processingEnv.messager.printMessage(Diagnostic.Kind, msg)
来打印日志
注意: 若使用Diagnostic.Kind.ERROR打印,则会导致编译失败。
生成代码
注解的信息收集完成之后是不能直接使用的,因为是在编译期间,无法直接保存信息到运行期。所以需要生成对应的代码老保存需要的信息和功能
AbstractProcessor中提供了生成代码的辅助类:Filer, 在ProcessingEnvironment中。生成代码就是一个简单的创建文件,写入文本内容的过程。生成java源码有很著名的javapoet框架,不再赘述。
在kotlin中运行Processor时kapt, 来替代annotationProcessor。 也有KotlinPoet来对应javapoet。
生成代码还是比较方便的
当然,如果需要生成的源码文件比较简单,可以直接使用拼接字符串的形式生成代码,然后写入到文件中。
自动生成的源码文件在build文件夹下面,kotlin生成的文件的文件夹路径可以在options中获取到:
val path = processingEnv.options[“kapt.kotlin.generated”]
文件生成之后,在开发期间就可以直接使用该类了
由于通过注解能获取的信息的类型是非常有限的,而且最终都是以写入文件的形式保存,所以能保存的信息比较有限,用的最多的也就是来获取类名,写入到文件中,反射使用。当然,生成的代码要实现的功能还是可以更加丰富的,如ButterKnife,Router, dagger等
网友评论