KSP を使い始める
//: # (description: Kotlin Symbol Processing (KSP) に基づくアノテーションプロセッサーをプロジェクトに追加する方法、または KSP API を使用して独自のプロセッサーを作成する方法について説明します。)
このガイドでは、以下の内容について学びます:
- KSP ベースのアノテーションプロセッサーをプロジェクトに追加する方法。
- KSP API を使用して独自のアノテーションプロセッサーを作成する方法。
- プロセッサーによって生成されたコードがどこにあるか。
KSP ベースのプロセッサーをプロジェクトに追加する
プロジェクトで外部プロセッサーを使用するには、build.gradle(.kts) ファイルの plugins {} ブロックに KSP を追加します。プロセッサーが特定のモジュールでのみ必要な場合は、代わりにそのモジュールの build.gradle(.kts) ファイルに追加してください。
// build.gradle.kts
plugins {
kotlin("jvm") version "2.3.0"
id("com.google.devtools.ksp") version "2.3.3"
}// build.gradle
plugins {
id 'org.jetbrains.kotlin.jvm' version '2.3.0'
id 'com.google.devtools.ksp' version '2.3.3'
}KSP の最新バージョンを確認するには、GitHub の Releases をチェックしてください。
トップレベルの dependencies {} ブロックに、使用したいプロセッサーを追加します。この例では Moshi を使用していますが、他のプロセッサーでも手順は同じです。
// build.gradle.kts
dependencies {
ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.2")
}// build.gradle
dependencies {
ksp 'com.squareup.moshi:moshi-kotlin-codegen:1.15.2'
}独自のプロセッサーを作成する
以下の手順に従って、helloWorld() 関数を生成するシンプルなアノテーションプロセッサーを作成します。実用的ではありませんが、独自のプロセッサーとアノテーションを作成するための基本を理解できます。
プロジェクトに KSP を追加する
新しい Kotlin プロジェクトを作成し、KSP プラグインを追加します。
IntelliJ IDEA で、File | New | Project を選択します。
左側のリストで Kotlin を選択します。
ビルドシステムとして Gradle を選択し、Create をクリックします。

build.gradle(.kts)ファイルに KSP プラグインを追加します。kotlin// build.gradle.kts plugins { kotlin("jvm") version "2.3.0" id("com.google.devtools.ksp") version "2.3.3" apply false }groovy// build.gradle plugins { id 'org.jetbrains.kotlin.jvm' version '2.3.0' id 'com.google.devtools.ksp' version '2.3.3' apply false }
アノテーションを作成する
プロジェクトのルートに新しいモジュールを作成し、アノテーションを宣言します。
File | New | Module を選択します。
左側のリストで Kotlin を選択します。
以下のフィールドを指定して Create をクリックします。
- Name: annotations
- Build system: Gradle

モジュール内に
HelloWorldAnnotation.ktファイルを作成し、HelloWorldAnnotationという名前のアノテーションを宣言します。kotlin// annotations/src/main/kotlin/com/example/annotations/HelloWorldAnnotation.kt package com.example.annotations annotation class HelloWorldAnnotation
プロセッサーを作成して登録する
プロジェクトのルートに processor という名前の別のモジュールを作成します。
モジュールの
build.gradle(.kts)ファイルに、KSP API と宣言したアノテーションを依存関係として追加します。kotlin// processor/build.gradle.kts plugins { kotlin("jvm") } dependencies { implementation(project(":annotations")) implementation("com.google.devtools.ksp:symbol-processing-api:2.3.6") }groovy// processor/build.gradle plugins { id 'org.jetbrains.kotlin.jvm' } dependencies { implementation project ':annotations' implementation 'com.google.devtools.ksp:symbol-processing-api:2.3.6' }processor モジュール内に新しい
HelloWorldProcessor.ktファイルを作成し、以下のコードを追加します。kotlin// processor/src/main/kotlin/HelloWorldProcessor.kt class HelloWorldProcessor(val codeGenerator: CodeGenerator) : SymbolProcessor { // 1️⃣ process() 関数 override fun process(resolver: Resolver): List<KSAnnotated> { resolver .getSymbolsWithAnnotation("com.example.annotations.HelloWorldAnnotation") .filter { it.validate() } .filterIsInstance<KSFunctionDeclaration>() .forEach { it.accept(HelloWorldVisitor(), Unit) } return emptyList() } // 2️⃣ ビジター inner class HelloWorldVisitor : KSVisitorVoid() { override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) { createNewFileFrom(function).use { file -> file.write( """ fun helloWorld(): Unit { println("Hello world from function generated by KSP") } """.trimIndent() ) } } } // 3️⃣ createNewFileFrom() 関数 private fun createNewFileFrom(function: KSFunctionDeclaration): OutputStream { return codeGenerator.createNewFile( dependencies = createDependencyOn(function), packageName = "", fileName = "GeneratedHelloWorld" ) } // 3️⃣ createDependencyOn() 関数 private fun createDependencyOn(function: KSFunctionDeclaration): Dependencies { return Dependencies(aggregating = false, function.containingFile!!) } } // 文字列を OutputStream に書き込むためのユーティリティ関数 fun OutputStream.write(string: String): Unit { this.write(string.toByteArray()) }IDE で提案されるインポートを追加してください。
com.google.devtools.ksp.processingからResolverとDependenciesクラスをインポートするようにしてください。または、HelloWorldProcessor.ktの冒頭に以下の行をコピーしてください。kotlin// processor/src/main/kotlin/HelloWorldProcessor.kt import com.google.devtools.ksp.processing.CodeGenerator import com.google.devtools.ksp.processing.Dependencies import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSVisitorVoid import com.google.devtools.ksp.validate import java.io.OutputStreamコードの内容を見ていきましょう:
1️⃣
process()関数にはプロセッサーのメインロジックが含まれています。HelloWorldAnnotationでアノテーションされたすべてのシンボルを取得し、それぞれに対してHelloWorldVisitorを呼び出します。process()関数は、後のラウンドで処理するために、未処理のシンボルのリストを返します。この例では、安全にemptyList()を返しています。詳細については、複数ラウンドの処理を参照してください。2️⃣ プロセッサーは、ビジターを使用して KSP が提供する Kotlin 抽象構文木 (AST) のビューをトラバースします。
HelloWorldProcessorクラスの中にあるHelloWorldVisitorクラスがそのビジターです。HelloWorldAnnotationは関数にのみ使用されるため、visitFunctionDeclaration()のみをオーバーライドしています。KSVisitorVoidは KSP が提供するビジタークラスの 1 つで、オーバーライドして調整できます。KSVisitor<D, R>インターフェースを実装して、独自のビジターを作成することもできます。3️⃣
createNewFileFrom()は、KSP がコードを生成するファイルを作成します。createDependencyOn()は、生成された出力ファイルが、アノテーションが使用されているソースファイルに依存するようにします。KSP がファイルを生成・管理する方法について詳しく知るには、
CodeGeneratorインターフェースのソースコードを参照してください。
HelloWorldProcessorProvider.ktファイルを作成します。その中で、SymbolProcessorProviderを継承するHelloWorldProcessorProviderクラスを宣言します。kotlin// processor/src/main/kotlin/HelloWorldProcessorProvider.kt import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.processing.SymbolProcessorEnvironment import com.google.devtools.ksp.processing.SymbolProcessorProvider class HelloWorldProcessorProvider : SymbolProcessorProvider { override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { return HelloWorldProcessor(environment.codeGenerator) } }プロセッサープロバイダーを登録します。
resources/META-INF/servicesディレクトリにcom.google.devtools.ksp.processing.SymbolProcessorProviderという名前のファイルを作成し、プロバイダーの完全修飾名を追加します。text## processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider HelloWorldProcessorProvider
プロセッサーを使用する
これでプロセッサーをテストする準備が整いました。以下の手順に従ってクライアントモジュールを作成し、アノテーションが付いた要素に基づいてプロセッサーにコードを生成させます。
プロジェクトのルートに
appという名前のモジュールを作成します。モジュールの
build.gradle(.kts)ファイルで:plugins {}ブロックに KSP プラグインを追加します。dependencies {}ブロックに作成したプロセッサーとアノテーションを追加します。
例:
kotlin// app/build.gradle.kts plugins { kotlin("jvm") id("com.google.devtools.ksp") } dependencies { implementation(project(":annotations")) ksp(project(":processor")) }groovy// app/build.gradle plugins { id 'com.google.devtools.ksp' } dependencies { implementation project (':annotations') ksp project (':processor') }プロジェクトレベルの
settings.gradle(.kts)ファイルで、すべてのサブモジュールが自動的に含まれていることを確認します。kotlin// settings.gradle.kts include("annotations") include("app") include("processor")groovy// settings.gradle include 'processor' include 'annotations' include 'app'appモジュール内にMain.ktファイルを作成し、以下のコードを追加します。kotlin// app/src/main/kotlin/Main.kt import com.example.annotations.HelloWorldAnnotation @HelloWorldAnnotation fun main() { helloWorld() }main()関数はhelloWorld()を呼び出していますが、この関数はまだ存在しません。IDE はhelloWorld()を未定義の参照としてハイライトします。これは想定通りです。プロジェクトをビルドして実行すると、KSP がhelloWorld()関数を生成します。プログラムを実行します。コンソールに
helloWorld()関数の出力が表示されます。textHello world from function generated by KSPKSP は
GeneratedHelloWorld.ktファイルにコードを生成します:textapp/build/generated/ksp/main/kotlin/GeneratedHelloWorld.kt
プロジェクト構造を確認する
プロジェクトの最終的なファイル構造は以下のようになるはずです。
.
├── app
│ ├── build.gradle.kts
│ └── src
│ └── main
│ └── kotlin
│ └── Main.kt
├── annotations
│ ├── build.gradle.kts
│ └── src
│ └── main
│ └── kotlin
| └── com
| └── example
| └── annotations
| └── HelloWorldAnnotation.kt
├── processor
│ ├── build.gradle.kts
│ └── src
│ └── main
│ ├── kotlin
│ │ ├── HelloWorldProcessor.kt
│ │ └── HelloWorldProcessorProvider.kt
│ └── resources/META-INF/services
| └── com.google.devtools.ksp.processing.SymbolProcessorProvider
├── build.gradle.kts
└── settings.gradle.kts追加のファイルやディレクトリがある場合があります。
次のステップ
- この例の完全なコードは KSP リポジトリで確認できます。
- より複雑で実践的な例については、KSP リポジトリを参照してください。
- KSP サポートライブラリのリストを確認してください。
