Kotlin注解使用

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 annoations, RoundEnvironment env) { }

    @Override
    public Set 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实现之后不能直接使用,需要注册之后才能运行,有两种方式:

  1. 手动注册

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

  1. 自动注册

使用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等

你可能感兴趣的:(Kotlin注解使用)