Kotlin的注解和java的基本一致, 具體的細(xì)節(jié)可以看官方文檔
https://kotlinlang.org/docs/reference/annotations.html
比較大的區(qū)別是Kotlin不支持@Inherited元注解,雖然一般情況下從父類(lèi)使用注解的情況是非常少的。但總有人會(huì)碰到這樣的問(wèn)題。已經(jīng)有人提出這個(gè)問(wèn)題了,詳見(jiàn):https://youtrack.jetbrains.com/issue/KT-22265
注解的使用
注解一般用來(lái)在編譯時(shí)處理代碼,例如編譯時(shí)進(jìn)行格式檢查,生成文檔等
Kotlin的注解和Java的注解使用方式基本一致。獲取注解相關(guān)信息的方式也基本一致
都需要實(shí)現(xiàn)AbstractProcessor來(lái)獲取帶指定的注解的元素的信息
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初始化的時(shí)候會(huì)調(diào)用此方法, ProcessingEnvironment是Processor所處的環(huán)境. ProcessingEnvironment有一個(gè)Options字段,用來(lái)存放一些特定的選項(xiàng),例如可以從gradle插件中傳遞Project的一些信息進(jìn)來(lái).
android.defaultConfig.javaCompileOptions.annotationProcessorOptions.argument(“moduleName”, project.name)
process 是處理注解的主要方法,annoations中包含注解和使用注解的元素的信息,RoundEnvironment包含當(dāng)前注解環(huán)境的上下文信息。return true表示該注解已處理完成,不再需要其他Processor處理
getSupportedAnnotationTypes 告訴Processor要掃面那些注解,返回的是包含指定注解類(lèi)名的set
getSupportedSourceVersion 指定支持的version, 不同的Version支持的內(nèi)容不一樣,
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 中的對(duì)象是TypeElement, TypeElement 是Element的子類(lèi),里面包含著注解的信息.
通過(guò)roundEnvironment.getElementsAnnotatedWith(注解類(lèi)的Class)來(lái)獲取當(dāng)前注解的信息
Element的關(guān)鍵屬性:
- name: 使用注解的元素的名稱(chēng)。如果是CLASS就是類(lèi)全名,如果是方法就是方法名,其他類(lèi)推
- getKind(): 使用注解的元素類(lèi)型,如CLASS, PACKAGE, INTERFACE,FIELD等,對(duì)應(yīng)注解的Target
- getModifiers(): 使用注解的元素的修飾符,如class的private, static, final等
- TypeMirror:對(duì)應(yīng)Java 編程語(yǔ)言中的類(lèi)型。 如ArrayType,DeclaredType,NullType等。主要用來(lái)判斷使用者和注解參數(shù)的類(lèi)型,通過(guò)typeMirror可以獲取注解中Class參數(shù)的類(lèi)名
注冊(cè)Processor
AbstractProcessor實(shí)現(xiàn)之后不能直接使用,需要注冊(cè)之后才能運(yùn)行,有兩種方式:
- 手動(dòng)注冊(cè)
在實(shí)現(xiàn)AbstractProcessor的項(xiàng)目中添加resources/META-INF文件夾,并在META-INF下添加一個(gè)名稱(chēng)為javax.annotation.processing.Processor的文本文件,在里面寫(xiě)入實(shí)現(xiàn)AbstractProcessor類(lèi)的全名
- 自動(dòng)注冊(cè)
使用google提供的AutoService主動(dòng)注冊(cè)。在AbstractProcessor實(shí)現(xiàn)類(lèi)上加上注解:
@AutoService(Processor::class)
就可以了。
AutoService也是通過(guò)注解的形式自動(dòng)生成對(duì)應(yīng)的文件和文件夾。
打印日志
由于AbstractProcessor的執(zhí)行在編譯器,所以不能直接使用android和java的日志輸出方式,需要使用
processingEnv.messager.printMessage(Diagnostic.Kind, msg)
來(lái)打印日志
注意: 若使用Diagnostic.Kind.ERROR打印,則會(huì)導(dǎo)致編譯失敗。
生成代碼
注解的信息收集完成之后是不能直接使用的,因?yàn)槭窃诰幾g期間,無(wú)法直接保存信息到運(yùn)行期。所以需要生成對(duì)應(yīng)的代碼老保存需要的信息和功能
AbstractProcessor中提供了生成代碼的輔助類(lèi):Filer, 在ProcessingEnvironment中。生成代碼就是一個(gè)簡(jiǎn)單的創(chuàng)建文件,寫(xiě)入文本內(nèi)容的過(guò)程。生成java源碼有很著名的javapoet框架,不再贅述。
在kotlin中運(yùn)行Processor時(shí)kapt, 來(lái)替代annotationProcessor。 也有KotlinPoet來(lái)對(duì)應(yīng)javapoet。
生成代碼還是比較方便的
當(dāng)然,如果需要生成的源碼文件比較簡(jiǎn)單,可以直接使用拼接字符串的形式生成代碼,然后寫(xiě)入到文件中。
自動(dòng)生成的源碼文件在build文件夾下面,kotlin生成的文件的文件夾路徑可以在options中獲取到:
val path = processingEnv.options[“kapt.kotlin.generated”]
文件生成之后,在開(kāi)發(fā)期間就可以直接使用該類(lèi)了
由于通過(guò)注解能獲取的信息的類(lèi)型是非常有限的,而且最終都是以寫(xiě)入文件的形式保存,所以能保存的信息比較有限,用的最多的也就是來(lái)獲取類(lèi)名,寫(xiě)入到文件中,反射使用。當(dāng)然,生成的代碼要實(shí)現(xiàn)的功能還是可以更加豐富的,如ButterKnife,Router, dagger等