Kotlin アノテーション(Annotations)

Kotlin アノテーション

アノテーションは、コンパイル時にクラス、インターフェース、パラメータなどへメタデータを付与するために使用される。アノテーションはコンパイラで使用でき、ランタイムにも反映できる。アノテーションの値に応じて、データまたはプログラムの意味を変更できる。

Kotlin メタアノテーション

アノテーションを宣言するときにメタ情報を追加できる。次は主なメタアノテーションである。

アノテーション名 使用
@Target このアノテーションは、アノテーションを適用できる要素の種類を指定する。
たとえば、クラス、関数、プロパティなどにアノテーションを適用できるように指定できる。
@Retention このアノテーションは、アノテーションが保持される期間を指定する。
Kotlinでは3つの保持ポリシーを提供する: SOURCEBINARYRUNTIMESOURCEはコンパイル後に破棄され、BINARYはコンパイル済みクラスファイルに含まれるがランタイムでは使用できず、RUNTIMEはランタイムで使用可能である。
@Repeatable このアノテーションは、同じ要素に複数回適用できるようにする。Kotlin 1.4からサポートされている。
@MustBeDocumented このアノテーションは、文書化が必要なアノテーションであることを示す。つまり、このアノテーションを使用するときは必ず文書化されなければならない。

アノテーションの例

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class MyAnnotation

アノテーションの作成

アノテーションは、クラスの前にアノテーション修飾子を記述すればよい。

annotation class MyAnnotation  

コンストラクタへのアノテーション宣言

クラスのコンストラクタにアノテーションを指定することもできる。コンストラクタ宣言にconstructorキーワードを追加し、その前にアノテーションを記述すればよい。

Kotlinでコンストラクタにアノテーションを宣言する方法は、主にプライマリコンストラクタ(primary constructor)に適用される。次はコンストラクタにアノテーションを宣言する例である。

class MyClass @Inject constructor() {
    // クラス内容
}

上の例で、@Injectアノテーションはクラスのコンストラクタに適用されている。この場合、MyClassのプライマリコンストラクタが@Injectアノテーションで処理される。

コンストラクタのパラメータにアノテーションを使用することもできる。

class MyClass {
    constructor(@SomeAnnotation parameter: String) {
        // コンストラクタ内容
    }
}

上の例で、parameterパラメータに@SomeAnnotationアノテーションが適用されている。

Propertyのaccessorアノテーション宣言

class MyClass{  
    var parameter: String? = null
        @Inject set  
}  

アノテーションを作成するときのコンストラクタ使用

アノテーションを作成するとき、コンストラクタを使用することもできる。コンストラクタをアノテーションとして使用するには、パラメータが必要である。

annotation class MyClass(val parameter: String)

@MyClass("parameter")
class Foo {
    // ...
}

アノテーションで使用されるパラメータはnullable型にできない。これは、JVMがアノテーションプロパティの値としてnullをサポートしていないためである。

また、1つのアノテーションを別のアノテーションのパラメータとして使用できるが、この場合は接頭辞@文字を付けてはならない。

annotation class ReplaceWith(val expression: String)

annotation class Deprecated(
    val message: String,
    val replaceWith: ReplaceWith = ReplaceWith(""), // @を付けていない。
)

@Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))
class Foo2 {
    // ...
}

また、KotlinのKClassを使用してクラスをアノテーションのパラメータとして指定すると、KotlinコンパイラはこれをJavaクラスに自動変換し、アノテーションと引数を正常に参照できるようにする。

import kotlin.reflect.KClass

annotation class MyClass(val arg1: KClass<*>, val arg2: KClass<out Any>)

@MyClass(String::class, Int::class)
class Foo

TYPEアノテーションの使用

JavaアノテーションインターフェースAnn.javaを作成する。

package basic.annotations.ex5;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Ann {
    int value();
}

Annアノテーションインターフェースを使用するMyClass.ktクラスを作成する。

@Ann(value = 10)
class MyClass {
    // ...
}

fun main(args: Array<String>) {
    val clazz = MyClass()
    val x = clazz.javaClass.getAnnotation(Ann::class.java)
    if (x != null) {
        println("Value:" + x?.value)
    }
}

Output:

Value: 10