Kotlinにおけるアノテーション(Annotation)は、クラスや関数などのコード要素に付与する「メタデータ」です。
アノテーション自体が直接処理を実行することはなく、コンパイラ・ツール・フレームワーク・コード生成処理などが、その情報を読み取って振る舞いを決定するために使われます。
Javaにも同様の仕組みがありますが、Kotlinでは
- プロパティ構造の違い
- use-site target(適用先指定)
- JVM / JS / Native というマルチプラットフォーム前提
といった点により、より厳密な理解が必要になります。
アノテーションの基本的な役割
アノテーションは次のような目的で利用されます。
- コンパイラへの指示(非推奨、警告抑制など)
- フレームワークによる自動処理(DI、バリデーション、ルーティング)
- 実行時の情報取得(リフレクション)
- コンパイル時のコード生成(KAPT / KSP)
- 静的解析・Lint・テスト補助
重要なのは、「アノテーションを付けただけでは何も起きない」という点です。
必ず「それを読む側(コンパイラ、フレームワーク、ツール)」が存在します。
Kotlinでの基本的な記述方法
シンプルなアノテーションの使用例
@Deprecated("この関数は使用しないでください")
fun oldFunction() {}
Kotlinでは @ を付けて宣言し、Java同様に関数・クラスなどに付与できます。
引数を持つアノテーション
@Deprecated(
message = "新しい関数を使用してください",
replaceWith = ReplaceWith("newFunction()")
)
fun oldFunction() {}
Kotlinは名前付き引数を使えるため、アノテーションの意図が明確になりやすいのが特徴です。
Kotlin標準の代表的なアノテーション
@Deprecated
非推奨を示すためのアノテーションです。
@Deprecated(
"Use newFunction instead",
level = DeprecationLevel.WARNING
)
fun oldFunction() {}
level には以下があります。
WARNING:警告を表示ERROR:コンパイルエラーHIDDEN:参照不可(事実上の削除)
@Suppress
特定の警告を抑制します。
@Suppress("UNUSED_VARIABLE")
fun sample() {
val x = 10
}
必要最小限の範囲で使うことが推奨されます。
Java相互運用向けアノテーション
@JvmStatic@JvmField@JvmOverloads
これらは Kotlinの構文をJavaから扱いやすくするための補助です。
class Sample {
companion object {
@JvmStatic
fun hello() {}
}
}
@JvmOverloads は、デフォルト引数を持つ関数・コンストラクタに対してJava向けのオーバーロードを生成しますが、APIが膨らむため設計段階での検討が必要です。
use-site target(適用先指定)の重要性
Kotlinでは、アノテーションを「どこに付与するか」を明示できます。
class User(
@field:NotNull
val name: String
)
なぜ必要なのか?
Kotlinのプロパティは内部的に以下へ展開されます。
- コンストラクタ引数
- フィールド(条件付き)
- getter
- setter(varの場合)
そのため、どこにアノテーションが付いたかで、フレームワークの挙動が変わることがあります。
主な use-site target
| 指定 | 対象 |
|---|---|
field: | フィールド |
get: | getter |
set: | setter |
param: | コンストラクタ引数 |
property: | Kotlinプロパティ |
file: | ファイル |
例
@get:Deprecated("getter is deprecated")
val value: Int = 10
実務では
- バリデーション →
@field: - JSONシリアライザ / DI →
@get:
など、「誰が読むか」を前提に指定する必要があります。
独自アノテーションの定義
基本形
annotation class MyAnnotation
使用例
@MyAnnotation
class Sample
引数を持つ独自アノテーション
annotation class Loggable(val level: String)
@Loggable("DEBUG")
fun process() {}
使用可能な型の制約
- プリミティブ型
- String
- Enum
- 他のアノテーション
KClass<*>(JVM上ではClass相当)- 上記の配列
Retention(保持期間)
@Retention(AnnotationRetention.RUNTIME)
annotation class RuntimeAnnotation
| 種類 | 内容 |
|---|---|
SOURCE | ソースコードのみ |
BINARY | classファイルまで |
RUNTIME | 実行時リフレクションで参照可能 |
実行時に取得したい場合は RUNTIME が必須です。
Target(適用可能な対象)
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.FUNCTION
)
annotation class MyAnnotation
意図しない場所への使用を防ぐため、明示的に指定するのが推奨されます。
実行時取得とリフレクション
JVM環境では、アノテーションは以下の方法で取得できます。
- Javaリフレクション(追加依存なし)
- Kotlinリフレクション(
kotlin-reflectが必要)
val annotations = Sample::class.annotations
※ kotlin-reflect は便利ですが、バイナリサイズ・初期化コストが増えるため注意が必要です。
マルチプラットフォームでの注意点
- Kotlin/JVM:実行時リフレクション前提の設計が可能
- Kotlin/JS / Kotlin/Native:
- JVMのようなリフレクション前提は取りづらい
- コンパイル時処理(KAPT / KSP)やコード生成が中心
この違いを理解せずに設計すると、プラットフォーム移行時に破綻します。
注意点とベストプラクティス
- アノテーションは「誰が読むか」を常に意識する
- use-site targetを省略しない
- RUNTIMEアノテーションはコストを理解したうえで使う
- 魔法の仕組みとして乱用しない
まとめ
- Kotlinのアノテーションはメタデータであり、処理そのものではない
- use-site targetがJavaとの最大の違いであり、最重要ポイント
TargetとRetentionは設計段階で必ず定義する- JVMと非JVMでは設計思想が異なる
- フレームワーク理解・設計力に直結する基礎知識
以上、Kotlinのアノテーションについてでした。
最後までお読みいただき、ありがとうございました。










