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
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
170
CameraX使ってみた
takuji31
0
320
kotlinx.datetime 使ってみた
takuji31
0
1.1k
HiltのCustom Componentについて
takuji31
0
450
java.timeをAndroidで使う
takuji31
0
220
KSPを使ってコード生成
takuji31
0
490
kotlinx.serialization
takuji31
0
710
kanmoba-returns-02.pdf
takuji31
0
300
AndroidXとKotlin Coroutines
takuji31
0
450
Other Decks in Technology
See All in Technology
Azure Serverless 2026:Production-ready な AI エージェント基盤 / Azure Serverless 2026: Production-Ready AI Agent Platform
miyake
2
590
【ゲームメーカーズスクランブル2026】『Shadowverse: Worlds Beyond』UIとアニメーションで実現する最高のユーザー体験を叶えるプロトタイピング
cygames
PRO
1
360
事業課題から技術的負債に向き合う
sansantech
PRO
2
2.3k
高負荷プロダクション環境におけるAWS Lambdaのリアル 〜スケールとコストを左右する実行ライフサイクルの技術仕様〜
maimyyym
2
550
顧客に向き合う開発組織へ。リアーキテクチャとフィーチャーチーム化で挑む組織改革
safie
0
2.4k
aws-iot-platform-architecture-use-cases.pdf
ma2shita
0
650
リアーキテクチャ後の障害ゼロを目指したShadow Testingの取り組み
nihonbuson
PRO
1
180
ADKで始める業務改善 - AIエージェント開発時の考えと設計
harappa80
2
290
.NET WebAssemblyで実現するクライアントサイドAI推論:NuGetからViteまで、2つのエコシステムを繋ぐビルド戦略
yamachu
1
740
その Lambda、8分で 管理者権限まで奪われます
k1nakayama
7
3.7k
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
16
120k
開発投資の期待値を上げるプロダクトロードマップづくり ~プロダクトエンジニアが越境して事業を伸ばす~
kekekenta
1
250
Featured
See All Featured
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.2k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
590
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
250
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Color Theory Basics | Prateek | Gurzu
gurzu
1
470
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
490
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
390
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
410
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
920
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
340
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
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