Kotlinのアノテーションについて

採用はこちら

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ソースコードのみ
BINARYclassファイルまで
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との最大の違いであり、最重要ポイント
  • TargetRetention は設計段階で必ず定義する
  • JVMと非JVMでは設計思想が異なる
  • フレームワーク理解・設計力に直結する基礎知識

以上、Kotlinのアノテーションについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次