実践的なリフレクション
アノテーションを動的に読み取ります
「実践的なリフレクション」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
アノテーションとリフレクション
RUNTIME保持のアノテーションは、実行時にリフレクションで見つけられます。この組み合わせは、シリアライザー、バリデーター、依存性注入を支えています。
このレッスンでは、独自のアノテーションを動的に読み取ります。
クラスのアノテーションを読み取る
すべてのKClassはannotationsリストを公開します。このリストを調べると、特定の型のアノテーションを見つけられます。
@Retention(AnnotationRetention.RUNTIME)
annotation class Entity(val table: String)
@Entity("users")
class User
fun main() {
val ann = User::class.annotations
.filterIsInstance<Entity>()
.first()
println(ann.table)
}findAnnotationヘルパー
findAnnotation拡張関数を使うと、手動でフィルタリングするより簡潔に記述できます。アノテーション、またはnullを返します。
import kotlin.reflect.full.findAnnotation
@Retention(AnnotationRetention.RUNTIME)
annotation class Entity(val table: String)
@Entity("orders")
class Order
fun main() {
val ann = Order::class.findAnnotation<Entity>()
println(ann?.table)
}プロパティのアノテーション
プロパティは独自のアノテーションを持てます。memberPropertiesを反復処理し、それぞれのプロパティのannotationsを調べます。
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.findAnnotation
@Retention(AnnotationRetention.RUNTIME)
annotation class Column(val name: String)
class Product(@Column("product_id") val id: Int, val title: String)
fun main() {
Product::class.memberProperties.forEach { prop ->
val col = prop.findAnnotation<Column>()
if (col != null) println(prop.name + " -> " + col.name)
}
}ミニシリアライザーの構築
プロパティの読み取りとアノテーションを組み合わせて、出力を生成します。ここでは、カラム名が指定されている場合はそれを使い、各プロパティをkey=value形式の文字列に変換します。
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.findAnnotation
@Retention(AnnotationRetention.RUNTIME)
annotation class Column(val name: String)
class Item(@Column("item_id") val id: Int, val name: String)
fun main() {
val item = Item(7, "Book")
val parts = Item::class.memberProperties.map { p ->
val key = p.findAnnotation<Column>()?.name ?: p.name
key + "=" + p.getter.call(item)
}
println(parts.joinToString(", "))
}マーカーでスキップする
マーカーアノテーションを使うと、無視するプロパティを示せます。hasAnnotationでその存在を確認します。
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.hasAnnotation
@Retention(AnnotationRetention.RUNTIME)
annotation class Transient2
class Account(val id: Int, @Transient2 val secret: String)
fun main() {
Account::class.memberProperties
.filterNot { it.hasAnnotation<Transient2>() }
.forEach { println(it.name) }
}アノテーション引数の読み取り
アノテーションのインスタンスを取得したら、そのパラメーターは通常のプロパティです。フィールドと同じように読み取れます。
import kotlin.reflect.full.findAnnotation
@Retention(AnnotationRetention.RUNTIME)
annotation class Validated(val min: Int, val max: Int)
@Validated(min = 1, max = 100)
class Quantity
fun main() {
val v = Quantity::class.findAnnotation<Validated>()!!
println("range " + v.min + ".." + v.max)
}関数のアノテーション
関数にもアノテーションを付けて調べることができます。テストランナーがテストメソッドを見つけるように、フレームワークはこれを使ってハンドラーを見つけます。
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.findAnnotation
@Retention(AnnotationRetention.RUNTIME)
annotation class Route(val path: String)
class Api {
@Route("/home")
fun home() = "home page"
}
fun main() {
Api::class.memberFunctions.forEach { f ->
f.findAnnotation<Route>()?.let { println(f.name + " @ " + it.path) }
}
}動作を実行する
ルートアノテーションを読み取り、実際に呼び出しを振り分けます。これがルーティングフレームワークの動作の本質です。
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.findAnnotation
@Retention(AnnotationRetention.RUNTIME)
annotation class Route(val path: String)
class Api {
@Route("/ping")
fun ping() = "pong"
}
fun main() {
val api = Api()
val target = "/ping"
Api::class.memberFunctions.forEach { f ->
if (f.findAnnotation<Route>()?.path == target) {
println(f.call(api))
}
}
}実際の用途
アノテーションを利用したリフレクションは、多くのライブラリの基盤になっています。
- JSONシリアライズでフィールドをキーにマッピングする
- 制約を適用するバリデーション
- パスをハンドラーに対応付けるルーティング
- コンポーネントを接続する依存性注入
対象を絞って使う
リフレクションは、セットアップやフレームワークコードなど、1回またはまれにしか実行されない処理に限定するのが最適です。可能な場合は結果をキャッシュしてください。リクエストごとのホットパスでは、コンパイル時処理を優先してください。
クイックチェック
実践的なリフレクションについて理解度を確認しましょう。
振り返り
アノテーションとリフレクションを組み合わせて、次のことができるようになりました。
- クラス、プロパティ、関数のアノテーションを見つける
- 実行時にアノテーションの引数を読み取る
- ミニシリアライザーとルートディスパッチャーを構築する
- マーカーアノテーションが付いたフィールドをスキップする
実際のフレームワークはこのように構築されています。
よくある質問
「実践的なリフレクション」レッスンは無料ですか?
はい。「実践的なリフレクション」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「実践的なリフレクション」で何を学びますか?
アノテーションを動的に読み取ります ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「実践的なリフレクション」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- アノテーションの使用
- アノテーションの定義
- リフレクションの基礎
- 実践的なリフレクション