Kotlin Symbol Processing API
Kotlin Symbol Processing (KSP) は、Kotlin 用のソースコード生成フレームワークです。KSP API を使用すると、ソースコード内の アノテーション に基づいてコードを生成するプロセッサを作成できます。
KSP は、軽量なコンパイラプラグインの作成を簡素化することを目指しています。適切に定義された API によってコンパイラの変更が隠蔽されているため、プロセッサのメンテナンスに多大な労力を割く必要がありません。ただし、このアプローチにはトレードオフもあります。例えば、KSP ベースのプロセッサは、式(expression)や文(statement)を調査することはできず、ソースコードを変更することもできません。
KSP ベースのプラグインの代表的なユースケースには、以下が含まれます:
最初の KSP ベースのプロセッサを作成する方法については、KSP クイックスタート をご覧ください。
概要
KSP API は、Kotlin プログラムを慣用的に処理します。KSP は、拡張関数、宣言区の変異(declaration-site variance)、ローカル関数といった Kotlin 特有の機能を理解しています。また、型を明示的にモデル化し、等価性や代入互換性などの基本的な型チェックも提供します。
この API は、Kotlin の文法 に従って、プログラム構造をシンボルレベルでモデル化します。KSP ベースのプラグインがソースプログラムを処理する際、クラス、クラスメンバー、関数、および関連するパラメータなどの構成要素にはプロセッサからアクセスできますが、if ブロックや for ループなどはアクセス対象外となります。
概念的に、KSP は Kotlin リフレクションの KType に似ています。この API を使用すると、プロセッサはクラス宣言から特定の型引数を持つ対応する型へ、またその逆へとナビゲートできます。また、型引数の置換、変異(variance)の指定、スター投影(star projections)の適用、型の NULL 許容性のマークなども可能です。
KSP の別の捉え方として、Kotlin プログラムのプリプロセッサフレームワークと考えることもできます。KSP ベースのプラグインを「シンボルプロセッサ(symbol processors)」、あるいは単に「プロセッサ」と呼ぶ場合、コンパイルにおけるデータフローは以下のステップで説明できます。
- プロセッサがソースプログラムとリソースを読み取り、分析する。
- プロセッサがコードまたはその他の形式の出力を生成する。
- Kotlin コンパイラが、ソースプログラムを生成されたコードと一緒にコンパイルする。
本格的なコンパイラプラグインとは異なり, プロセッサはコードを変更することはできません。言語のセマンティクス(意味論)を変更するコンパイラプラグインは、時に非常に混乱を招くことがあります。KSP は、ソースプログラムを読み取り専用として扱うことで、その問題を回避しています。
KSP の概要については、こちらの動画(英語)でもご確認いただけます:
KSP がソースファイルをどのように見るか
ほとんどのプロセッサは、入力ソースコードのさまざまなプログラム構造を辿ります。API の使用方法に入る前に、KSP の視点からファイルがどのように見えるかを確認してみましょう。
KSFile
packageName: KSName
fileName: String
annotations: List<KSAnnotation> (ファイルの注釈)
declarations: List<KSDeclaration>
KSClassDeclaration // クラス、インターフェース、オブジェクト
simpleName: KSName
qualifiedName: KSName
containingFile: String
typeParameters: KSTypeParameter
parentDeclaration: KSDeclaration
classKind: ClassKind
primaryConstructor: KSFunctionDeclaration
superTypes: List<KSTypeReference>
// 内部クラス、メンバー関数、プロパティなどを含む
declarations: List<KSDeclaration>
KSFunctionDeclaration // トップレベル関数
simpleName: KSName
qualifiedName: KSName
containingFile: String
typeParameters: KSTypeParameter
parentDeclaration: KSDeclaration
functionKind: FunctionKind
extensionReceiver: KSTypeReference?
returnType: KSTypeReference
parameters: List<KSValueParameter>
// ローカルクラス、ローカル関数、ローカル変数などを含む
declarations: List<KSDeclaration>
KSPropertyDeclaration // グローバル変数
simpleName: KSName
qualifiedName: KSName
containingFile: String
typeParameters: KSTypeParameter
parentDeclaration: KSDeclaration
extensionReceiver: KSTypeReference?
type: KSTypeReference
getter: KSPropertyGetter
returnType: KSTypeReference
setter: KSPropertySetter
parameter: KSValueParameterこのビューには、ファイル内で宣言されている一般的な要素(クラス、関数、プロパティなど)がリストされています。
SymbolProcessorProvider: エントリポイント
KSP は、SymbolProcessor をインスタンス化するために SymbolProcessorProvider インターフェースの実装を必要とします。
interface SymbolProcessorProvider {
fun create(environment: SymbolProcessorEnvironment): SymbolProcessor
}また、SymbolProcessor は次のように定義されています。
interface SymbolProcessor {
fun process(resolver: Resolver): List<KSAnnotated> // これに注目します
fun finish() {}
fun onError() {}
}Resolver は、シンボルなどのコンパイラの詳細へのアクセスを SymbolProcessor に提供します。すべてのトップレベル関数と、トップレベルクラス内の非ローカル関数を見つけるプロセッサは、以下のようになります。
class HelloFunctionFinderProcessor : SymbolProcessor() {
// ...
val functions = mutableListOf<KSFunctionDeclaration>()
val visitor = FindFunctionsVisitor()
override fun process(resolver: Resolver) {
resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
}
inner class FindFunctionsVisitor : KSVisitorVoid() {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
classDeclaration.getDeclaredFunctions().forEach { it.accept(this, Unit) }
}
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
functions.add(function)
}
override fun visitFile(file: KSFile, data: Unit) {
file.declarations.forEach { it.accept(this, Unit) }
}
}
// ...
class Provider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = TODO()
}
}リソース
- クイックスタート
- なぜ KSP を使うのか?
- 例 (Examples)
- KSP がどのように Kotlin コードをモデル化するか
- Java アノテーションプロセッサ作成者のためのリファレンス
- インクリメンタル処理に関するメモ
- マルチラウンド処理に関するメモ
- マルチプラットフォームプロジェクトでの KSP
- コマンドラインからの KSP の実行
- FAQ
サポートされているライブラリ
以下の表は、Android で人気のライブラリと、それらの KSP サポート状況のリストです。
| ライブラリ | ステータス |
|---|---|
| Room | 公式サポート済み |
| Moshi | 公式サポート済み |
| RxHttp | 公式サポート済み |
| Kotshi | 公式サポート済み |
| Lyricist | 公式サポート済み |
| Lich SavedState | 公式サポート済み |
| gRPC Dekorator | 公式サポート済み |
| EasyAdapter | 公式サポート済み |
| Koin Annotations | 公式サポート済み |
| Glide | 公式サポート済み |
| Micronaut | 公式サポート済み |
| Epoxy | 公式サポート済み |
| Paris | 公式サポート済み |
| Auto Dagger | 公式サポート済み |
| SealedX | 公式サポート済み |
| Ktorfit | 公式サポート済み |
| Mockative | 公式サポート済み |
| Kotest | 公式サポート済み |
| DeeplinkDispatch | airbnb/DeepLinkDispatch#323 経由でサポート |
| Dagger | アルファ |
| Motif | アルファ |
| Hilt | 進行中 |
| Auto Factory | 未対応 |
