Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Kotlin Symbol Processing API (KSP) を使って Kotlin ...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Takuji Nishibayashi
December 10, 2022
Technology
3.3k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Kotlin Symbol Processing API (KSP) を使って Kotlin ア プリケーションの開発を効率化する
Takuji Nishibayashi
December 10, 2022
More Decks by Takuji Nishibayashi
See All by Takuji Nishibayashi
compose-hot-reload を試そうとした話
takuji31
0
190
CameraX使ってみた
takuji31
0
340
kotlinx.datetime 使ってみた
takuji31
0
1.2k
HiltのCustom Componentについて
takuji31
0
460
java.timeをAndroidで使う
takuji31
0
220
KSPを使ってコード生成
takuji31
0
510
kotlinx.serialization
takuji31
0
730
kanmoba-returns-02.pdf
takuji31
0
320
AndroidXとKotlin Coroutines
takuji31
0
460
Other Decks in Technology
See All in Technology
The future of architectural work
ufried
0
190
AIエージェントの監視、思考を見るか行動を見るか / Monitoring AI Agents: Thoughts or Actions
yusukeshimizu
2
180
cdkd (CDK Direct)
gotok365
4
280
【dbts2026】AIエージェントの 判断と探索を変える、 データベース エンジニアリング― 既存DBの処理と依存関係から作る、オペレーショナルオントロジー ―
shisyu_gaku
0
270
PostgreSQL オプティマイザ統計の秘密
nori_shinoda
1
450
生成AI時代のIAMのマニアックな話
takuros
6
2.9k
AI時代における医療情報システムのセキュリティ / Security of Healthcare IT Systems in the AI Era
henryofficial
0
130
Context Ontology Accelerator 入門 (業務データの意味を、AI エージェントに渡す)
inariku
PRO
3
610
公共システムAdventCalendar2026
toru_kubota
0
290
FinOpsを導入してマルチプロダクトのコスト最適化を実現する
kworkdev
PRO
0
140
AWS Quick 入門 | 目指せ Quick マスター 01
inariku
PRO
2
270
セキュリティ専任チームなしで攻撃を先回りするSREが実践したSIEM on Amazon OpenSearch Service
cscengineer
PRO
1
730
Featured
See All Featured
A better future with KSS
kneath
240
18k
Site-Speed That Sticks
csswizardry
13
1.6k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
60k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
530
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
580
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.3k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
121
130k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
450
Done Done
chrislema
187
17k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.8k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
Navigating Weather and Climate Data
rabernat
0
590
Transcript
Kotlin Symbol Processing API (KSP) を使って Kotlin ア プリケーションの開発を効率化する Kotlin
Fest 2022 @takuji31
自己紹介 西林 拓志(にしばやし たくじ) Twitter/GitHub takuji31 Android アプリケーションエンジ ニア 株式会社はてな
テクノロジーソリューション 本部第 2 グループ マンガアプ リチーム所属 Kotlin 歴 8 年くらい 2
Kotlin Symbol Processing API (以下 KSP) 使ってます か? 3
今日は KSP のプロセッサーの作り方(≠ 使い方)について話 します 4
今日話すこと KSP とは KSP を使う理由 プロセッサーの作り方 インクリメンタル処理 マルチラウンド処理 マルチモジュールでの活用方法 テスト
5
今日話さないこと KSP の使い方、セットアップ方法 Gradle 以外で KSP のプロセッサーを開発する方法 Kotlin Multiplatform での使い方
どういった時に KSP を使うとよいか (質問があれば答えます) etc. 6
注意点 スライド内に出てくる Gradle script は Kotlin DSL です、Groovy は公式ドキュメントみ てください
https://kotlinlang.org/docs/ksp-overview.html スライド内のコードは import や package を省略しています 7
KSP とは 8
KSP とは Kotlin でシンボルを処理するための軽量コンパイラープラグイン Java の Pluggable Annotation Processing API
と同様にアノテーションを使う Kotlin の言語機能に対応している インクリメンタル処理対応 Kotlin Multiplatform 対応 https://github.com/google/ksp 9
KSP を使う理由 10
KSP を使う理由 - 課題解決 アノテーションを処理してコード生成をすることで普段の開発に潜む問題を解決する 頑張って型作って解決していたことをコード生成でカバーしたり Boilerplate コードを自動生成することでコード内のノイズを減らしたり 規模が大きなアプリケーションでモジュールごとに必要な設定を集約したり 型安全なクエリービルダーを作ったり
型安全な画面遷移を実現したり etc. 11
KSP を使う理由 - kapt と比べて kapt と比べて高速 kapt は一旦 Kotlin
から Java のスタブコードを生成しているがこれがとても遅い 現在開発しているアプリの場合だいたい全体のビルド時間の 20%くらいがスタブコ ード生成の時間 Kotlin の言語機能に対応した構造を返してくれるので、Pluggable Annotation Processing API で Kotlin のメタデータを頑張って読むみたいなことが不要 kotlinx-metadata-jvm なるものを使えばできるけどまあまあ難しい メンテナンスモードになってるのでこれ以上更新されない 今から Kotlin で新しくプロセッサーを作って使うのは厳しい 12
KSP を使う理由 - リフレクションと比べて ビルド時に型のチェックが行われるので安全 より高速 バイナリーサイズに影響なし (Android 的文脈で)難読化に強い 13
KSP を使う理由 - コンパイラープラグインと比べて 簡単 Kotlin のバージョンの影響を受けない(KSP のライブラリー自体は Kotlin のバージョンに
合わせる必要がある) 14
KSP を使う理由 - その他 Multiplatform 対応 Kotlin Multiplatform Mobile とかやっていると便利そう
私はやっていないので実際の使用感は不明 公式ドキュメントが充実していて始めやすい https://kotlinlang.org/docs/ksp-overview.html KotlinPoet と組み合わせることでプログラムの構造を簡単に作ることができる https://square.github.io/kotlinpoet/ 15
プロセッサーの 作り方 16
今回作るもの インターフェースにアノテーションをつけるとそのインターフェースを実装した抽象ク ラスを吐き出す 実用性はないが簡単な例ということで // これを @SimpleGeneration interface Hoge //
こうだ abstract class AbstractHoge: Hoge 17
プロセッサーの作り方 Gradle モジュールを作る SymbolProcessor を実装する Visitor を実装する SymbolProcessorProvider を作る サービスプロバイダーの設定をする
18
Gradle モジュールを作る 19
Gradle モジュールを作る 好きな IDE やツールでプロジェクトに Kotlin モジュールを新しく作りましょう 名前は自由 compiler processor
ksp-hogehoge 処理に使うアノテーションや生成されるコードで使うクラスは別のモジュールに分けて もよい 分かれている方が無駄なクラスがアプリケーションの classpath に含まれない etc. 20
build.gradle.kts // ... dependencies { // KSP のAPI implementation("com.google.devtools.ksp:symbol-processing-api:1.7.21-1.0.8") //
KotlinPoet implementation("com.squareup:kotlinpoet:1.12.0") // KotlinPoet のKSP 用拡張 implementation("com.squareup:kotlinpoet-ksp:1.12.0") } 21
SymbolProcessor を実装する 22
SymbolProcessor class ExampleSymbolProcessor( private val codeGenerator: CodeGenerator, private val logger:
KSPLogger ) : SymbolProcessor { override fun process(resolver: Resolver): List<KSAnnotated> { resolver .getSymbolsWithAnnotation(SimpleGeneration::class.qualifiedName!!) .filterIsInstance<KSClassDeclaration>() .forEach { it.accept(SimpleGenerationVisitor(codeGenerator, logger), Unit) } return emptyList() } } 23
Visitor class SimpleGenerationVisitor( private val codeGenerator: CodeGenerator, private val logger:
KSPLogger ) : KSVisitorVoid() { override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) { if (classDeclaration.classKind != ClassKind.INTERFACE) { logger.error("Only interface allowed", classDeclaration) return } val packageName = classDeclaration.packageName.asString() val className = ClassName(packageName, "Abstract" + classDeclaration.simpleName.asString()) val typeSpec = TypeSpec.classBuilder(className) .addModifiers(KModifier.ABSTRACT) .addSuperinterface(classDeclaration.toClassName()) FileSpec.builder(packageName, className.simpleName) .addType(typeSpec.build()) .build() .writeTo( codeGenerator, Dependencies( aggregating = false, classDeclaration.containingFile!! ) ) } } 24
SymbolProcessorProvider を作る 25
SymbolProcessorProvider class ExampleSymbolProcessorProvider : SymbolProcessorProvider { override fun create(environment: SymbolProcessorEnvironment):
SymbolProcessor { return ExampleSymbolProcessor(environment.codeGenerator, environment.logger) } } 26
サービスプロバイダーの設定をする 27
サービスプロバイダーの設定 // resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider jp.takuji31.kotlinfest2022.compiler.ExampleSymbolProcessorProvider 28
インクリメンタル 処理 29
インクリメンタル処理 KSP はインクリメンタル処理に対応している インクリメンタル処理のモードは 2 つ Isolated (分離) Aggregated (集約)
ファイルを書き出すときに Dependencies で依存を指定すれば、依存に変更があった時 に再処理される 生成されるファイルごとにモードが変えられる 30
Isolated (分離) 生成されたファイルが単一もしくは複数のファイルと紐付いている時のモード 依存に指定されたファイルが変更されると再処理される ↑ 以外のファイルが変更された時は処理されない 1 つのアノテーションで 1 つのファイルを生成したいときによく使う
例) アノテーションがつけられたインターフェースの実装クラスを生成する 31
Isolated (分離) Dependencies(aggregating = false, classDeclaration.containingFile!!) 32
Aggregated (集約) 生成されたファイルが不特定の複数のファイルと紐付いている時のモード 依存に指定されたファイル以外のものが変更されると依存に指定されたファイルとまと めて再処理される 基本的に変更があれば毎回処理されるイメージ 1 つのアノテーションで複数のファイルをまとめたファイルを作る時に使われる 例 1)
アノテーションがつけられたインターフェースをまとめたインターフェースを 作る 例 2) DI コンテナーで DI したいインスタンスの情報を収集する 例 3) 同じアノテーションがつけられた複数のクラスから特定のクラスだけを選んで 何か処理する 33
Aggregated (集約) val dependencies: Array<KSAnnotated> = // ... Dependencies(aggregating =
true, *dependencies.mapNotNull { it.containingFile }) 34
依存をちゃんと指定しないと「なぜかコード生成されな い」みたいな事態になる 35
マルチラウンド処理 36
マルチラウンド処理 処理できないシンボルの処理を後回しにする仕組み KSP のプロセッサーで生成したコードはすぐにプロセッサーで認識できない ラウンドを複数回繰り返して、そのラウンドで生成されたファイルがなくなったら終わ り 生成されたファイルがなくなったけど遅延されているシンボルがあればエラー マルチラウンド処理で活用するためにシンボルのバリデーションを行う仕組みがある カスタムでバリデーションルールを作れるが今回は説明しません 37
処理の遅延方法 override fun process(resolver: Resolver): List<KSAnnotated> { val symbolsWithAnnotation =
resolver .getSymbolsWithAnnotation(SimpleGeneration::class.qualifiedName!!) .filterIsInstance<KSClassDeclaration>() symbolsWithAnnotation .filter { it.validate() } .forEach { it.accept(SimpleGenerationVisitor(codeGenerator, logger), Unit) } return symbolsWithAnnotation.filter { !it.validate() }.toList() } 38
マルチモジュールでの活用方法 39
依存しているモジュールやライブラリーのシンボルは KSP の getSymbolsWithAnnotation で取得できな い google/ksp#1075 40
じゃあどうするのか? 41
getDeclarationsFromPackage を使う 42
getDeclarationsFromPackage を使う 特定のパッケージに含まれる定義を全部取り出すメソッド 特定のパッケージに何かしらのメタデータを書き出す 集約するモジュールで ↑ のパッケージに書かれた定義を読んでコード生成する 集約に使う用のアノテーションを作って集約したいモジュールで使う 43
テスト 44
コンパイルのテストってどうやんの? 45
tschuchortdev/kotlin-compile-testing 46
テストコード val source = SourceFile.kotlin( "ExampleClass.kt", """ package jp.takuji31.kotlinfest2022.compiler import
jp.takuji31.kotlinfest2022.compiler.annotation.SimpleGeneration @SimpleGeneration interface SimpleInterface { fun printHelloWorld() } """.trimIndent() ) val compilation = KotlinCompilation().apply { sources = listOf(source) inheritClassPath = true symbolProcessorProviders = listOf(ExampleSymbolProcessorProvider()) kspWithCompilation = true } val result = compilation.compile() assertThat(result.exitCode) .isEqualTo(KotlinCompilation.ExitCode.OK) 47
まとめ SymbolProcessor、Visitor で KSP のプロセッサーは作れる Kotlin のコード生成は KotlinPoet でやると楽 インクリメンタル処理のための依存は
Dependencies で指定 マルチラウンド処理をするためには process メソッドで遅延したいシンボルを渡す 複数モジュールのコードを集約したい時は getDeclarationsFromPackage プロセッサーのテストは kotlin-compile-testing で 48
ドキュメント/サンプルコード https://kotlinlang.org/docs/ksp-overview.html 公式ドキュメント https://github.com/google/ksp/tree/main/examples/playground 公式サンプル https://github.com/takuji31/kotlinfest2022-ksp-example 今回のスライドに出てきたソースコード https://github.com/takuji31/navigation-compose-screen もうちょっと複雑な例 49
Enjoy KSP Life! 50