Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレン...
Search
ternbusty
May 29, 2026
Programming
170
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
May 29, 2026
More Decks by ternbusty
See All by ternbusty
Open Source Summit North America 2026: Building a Shared, Persistent Virtual Filesystem for WebAssembly
ternbusty
1
86
CloudNative Days Winter 2025: 一週間で作る低レイヤコンテナランタイム
ternbusty
7
2.7k
JJUG CCC 2025 Fall: Virtual Thread Deep Dive
ternbusty
4
810
Server Side Kotlin Meetup vol.16: 内部動作を理解して ハイパフォーマンスなサーバサイド Kotlin アプリケーションを書こう
ternbusty
5
570
Other Decks in Programming
See All in Programming
スマートグラスで並列バイブコーディング
hyshu
0
130
Webフレームワークの ベンチマークについて
yusukebe
0
160
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
2k
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
740
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
3.8k
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
400
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
2.1k
3Dシーンの圧縮
fadis
1
770
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
120
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
190
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
150
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
200
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.3k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
BBQ
matthewcrist
89
10k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
250
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
44k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
65
55k
The untapped power of vector embeddings
frankvandijk
2
1.8k
Scaling GitHub
holman
464
140k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
290
Transcript
© LY Corporation JSpecify で実現する Kotlin フレンドリーな Java API 設計
LINEヤフー株式会社 早坂 絢⼦
© LY Corporation 2 Ayako Hayasaka LINEヤフー株式会社 Software Engineer 2023
年度⼊社 SWAT チーム所属 Web バックエンド領域で全社横断的な技術⽀援を実施 Java ⾔語サポートチーム所属 メインは Spring Boot + Java / Kotlin 外部登壇 • JJUG CCC 2025 Fall: Virtual Thread Deep Dive • CloudNative Days Winter 2025: ⼀週間で作る 低レイヤコンテナランタイム • Open Source Summit North America 2026: Building a Shared, Persistent Virtual Filesystem for WebAssembly OSS Contribute • Google Summer of Code 2026: Tail call support in the Kotlin/Wasm backend (Kotlin Foundation, 進⾏中) © LY Corporation 2
© LY Corporation 3 LINEヤフーでの Server Side Kotlin の広がり https://techblog.lycorp.co.jp/ja/20260318b
サーバーサイド開発で使⽤している開発⾔語はどれですか? Java Kotlin
© LY Corporation LINEヤフーでの Server Side Kotlin の広がり • LINEメッセージングプラットフォーム,
LINE公式アカウント, LINE Store, LINEギフト, LINEポイント, LINEミニアプリ, Yahoo!フリマ, Yahoo!カレンダー, Yahoo!ファイナンス など多くの採⽤事例・求⼈あり • 社内の Java サポートチームでも Server Side Kotlin のサポートを開始 • Java チームで提供しているライブラリを Kotlin から使う場合の サンプルレポジトリ提供 • Java エンジニアのための Kotlin ガイド等ドキュメント整備 • Java チームで提供しているライブラリを Kotlin から利⽤しやすく する対応 4
© LY Corporation LINEヤフーでの Server Side Kotlin の広がり • LINEメッセージングプラットフォーム,
LINE公式アカウント, LINE Store, LINEギフト, LINEポイント, LINEミニアプリ, Yahoo!フリマ, Yahoo!カレンダー, Yahoo!ファイナンス など多くの採⽤事例・求⼈あり • 社内の Java サポートチームでも Server Side Kotlin のサポートを開始 • Java チームで提供しているライブラリを Kotlin から使う場合の サンプルレポジトリ提供 • Java エンジニアのための Kotlin ガイド等ドキュメント整備 • Java チームで提供しているライブラリを Kotlin から利⽤しやすく する対応 5
© LY Corporation Java と null アノテーションの⻑く泥臭い歴史 Kotlin から Java
のライブラリを利⽤する際に困ること Java ライブラリ側で必要な対応 Platform Type の検出⽅法 まとめ 01 03 02 04 05 6 Agenda
© LY Corporation 前提知識: Java における null の課題 • Java
では、すべての参照型に null が代⼊可能 • 型レベルで、nullable か否かを表現することができない • 結果として、静的解析では null の有無を判定できず、実⾏時に初めて NullPointerException (NPE) が発⽣する → どうにかして、静的解析時に参照できるような、Nullability を表現する⽅法が 欲しい! 7 Annotation を付与することで Nullability を 表現する仕組みがあればいいのでは?
© LY Corporation 歴史: null 安全アノテーションの乱⽴ • JetBrains, Spring Framework
などがそれぞれ独⾃の @Nullable or @NotNull or @NonNull アノテーションを定義 • 同じ名前だが別物、IDE で警告が出ない等の問題が顕在化 • 統⼀されたアノテーションを作ろうとした JSR-305 (javax.annotations.*) も頓挫 nullの10億ドルの過ちから未来へ Spring Boot 4とJSpecifyが描くnull安全設計 8
© LY Corporation JSpecify の登場 • 2021 年に Google が⽴ち上げ、2024
年に 1.0.0 をリリース • Broadcom (Spring プロジェクト)、JetBrains、Oracle (OpenJDK)、 Uber (NullAway) など主要なステークホルダーに⽀えられている *1 • Spring Framework 7 および Spring Boot 4 以降で採⽤ *2 • Spring Boot 4 以降では Spring の主要な API は JSpecify アノテーション付き! • コレクションの中⾝の型等にも Annotation を付与できる *1: https://jspecify.dev/about/ *2: https://spring.io/blog/2025/03/10/null-safety-in-spring-apps-with-jspecify-and-null-away List<@Nullable String> role; 9
© LY Corporation 10 ⼀⽅そのころ Kotlin は……? Kotlin から Java
のライブラリを利⽤する際に困ること 02
© LY Corporation Kotlin の null 安全性 • Java と違い、null
を許容する型 (例: String?) とそうでない型 (例: String) を 型システムレベルで明⽰しているので、静的解析でエラーにできる じゃあ、Java にあるような アノテーションがどうこう みたいな問題とは無縁だね! 11
© LY Corporation Kotlin の null 安全性 • Java と違い、null
を許容する型 (例: String?) とそうでない型 (例: String) を 型システムレベルで明⽰しているので、静的解析でエラーにできる じゃあ、Java にあるような アノテーションがどうこう みたいな問題とは無縁だね! コトはそう単純ではない! 12
© LY Corporation Platform Type とは? • 問題は、Kotlin から Java
の関数を呼び出すときに発⽣する public String find() { return System.getProperty("x"); } val s = api.find() s.length Java Kotlin Kotlin からすると、find の返り値が null かそうでないかわからず、null かどうか 不明な Platform Type として解釈される (s の型は String!) 13 null かどうかわからないので null チェックも強制されない もし s の値が null だったらここで NPE が発⽣してしまう
© LY Corporation IDE での表⽰を確認 14 ホバーすると String! であることはわかるが 特に
IDE で警告はなく、 コンパイルエラーも出ない Java Kotlin 実⾏時 実⾏時には NPE が⽣じる
© LY Corporation Annotation をつけてみると? 15 • JSpecify の @Nullable
annotation がついているとどうなる? public @Nullable String find() { return System.getProperty("x"); } val s = api.find() s.length Java Kotlin アノテーションのおかげで s の型は String? になる コンパイルエラーになり、 null ハンドリングが強制される
© LY Corporation IDE での表⽰を確認 16 @Nullable アノテーション付与済み Java Kotlin
コンパイルエラーになり、 null ハンドリングが強制される
© LY Corporation Kotlin から解釈できる annotation 17 • Kotlin 1.1.50
でコンパイルオプション -Xjsr305=strict が登場 *1 • これを指定すると、@Nullable のついた変数の null ハンドリングが強制される (コンパイルエラーになる) • Kotlin 1.5.20 からは JSpecify のサポート開始 *2 • 2.0.20 からは JSpecify の全てのアノテーションを正しく解釈できるようになった • 当初はデフォルトでは warn 扱いだったが、Kotlin 2.1 からはエラー扱いに • コンパイラオプション -Xnullability-annotations で挙動を変更できる *3 • 現在解釈できる annotation は上記含む 9 種類 *4 *1: https://blog.jetbrains.com/kotlin/2017/09/kotlin-1-1-50-is-out/ *2: https://kotlinlang.org/docs/whatsnew1520.html#support-for-jspecify-nullness-annotations *3: https://jspecify.dev/docs/whether/#kotlin *4: https://kotlinlang.org/docs/java-interop.html#nullability-annotations
© LY Corporation Spring Boot 4 時代の nullability annotation 18
• Spring Boot 3.x は 2026 年 6 ⽉に EOL なので Spring Boot 4 を前提とすると…… • Spring Boot 4 では *1 • Spring の API に JSpecify Annotation 付与済み • Kotlin のベースラインは 2.1 に引き上げ • JSR-305 は事実上の休⽌状態 *2, Spring Framework の annotation も deprecated *3 *1: https://spring.io/blog/2025/12/18/next-level-kotlin-support-in-spring-boot-4 *2:https://jcp.org/en/jsr/detail?id=305 *3: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0.0-M2-Release-Notes 新たに nullability アノテーションを付与するなら JSpecify を使おう! JSR-305, Spring Framework annotation を 使っている⼈は JSpecify に移⾏しよう!
© LY Corporation 19 JSpecify のアノテーションって 具体的にどうつけたらいいの? Java ライブラリ側で必要な対応 03
© LY Corporation JSpecify のアノテーションは 4 種類 (1) 20 •
@Nullable • 型が null 許容である時に使う • フィールド、返り値、引数等に付与できる • @NonNull • 型が null を許容しない時に使う • 付与できる箇所は上と同じ • だが、次に⽰す @NullMarked の⽅を使う ケースが多く、こちらを使う機会は少なそう https://jspecify.dev/docs/user-guide/ static @Nullable String foo(@NonNull String x) { return x.isEmpty() ? null : x; } static @NonNull String bar(@Nullable String x) { return x == null ? "" : x; }
© LY Corporation JSpecify のアノテーションは 4 種類 (2) 21 •
@NullMarked • モジュール、パッケージ、クラス、メソッド等に 付与でき、対象を⼀括でnonnull 扱いにできる • @Nullable がある場合はそちらが優先 https://jspecify.dev/docs/user-guide/ @NullMarked class Strings { static @Nullable String foo(String x) { return x.isEmpty() ? null : x; } } • @NullUnmarked • NullMarked を打ち消して、何もアノテーションをつけていないのと同じ状態にする • コードベースに対して段階的にアノテーションを導⼊したい時に使⽤できる
© LY Corporation アノテーション付与戦略 22 • NonNull か Nullable かはどうやって判定する?
• 外部ライブラリの場合、まずは依存ライブラリのドキュメントを読もう • ドキュメントに記載がなく、実装から⼿掛かりを探るには…… • return null; があればそのメソッドの返り値は nullable であろう • もし if (parameter == null) みたいなのがあればそのパラメータは nullable であろう • あるフィールドが null あるいは null になりうる値を代⼊されていたら、その フィールドは nullable であろう https://jspecify.dev/docs/applying/
© LY Corporation アノテーション付与の順序 23 • 基本的には、他のクラスやパッケージへの依存が少ないクラスから始め、 それが終わったら呼び出し元へと外側へ進んでいく 1. null
になりうるものについて @Nullable を付与していく 1. 付与し終わったら @NullMarked をつける 2. まだ注釈付与が間に合っていない部分があればその部分に @NullUnmarked をつける 2. NullAway などの静的解析ツールによりチェック 3. Kotlin から呼び出してみて、Platform Type が⽣じないか確認 https://jspecify.dev/docs/applying/
© LY Corporation 補⾜: NullAway は何をチェックしてくれる? 24 • アノテーションと実装の齟齬や、アノテーション同⼠の⽭盾を検出 •
@NonNull と annotate した変数に null を代⼊している • 引数が @Nullable で、null チェックをせずそのまま値を返却しているが、 返り値の値は @NonNull になっている • 変数が @Nullable なのに、null に対して⾏うと NPE が発⽣する操作を ⾏っている • 逆に以下のようなものは検出できない • @NonNull でいいのに @Nullable になっている https://github.com/uber/NullAway/wiki/Error-Messages
© LY Corporation 実際の進め⽅ 25 • 先述の付与戦略を組み込んだ AI Agent ⽤の
skills を作成 (以下は指⽰の概略) 1. 複数モジュールからなるレポジトリの場合、他のクラスやパッケージへの依存が少ない モジュールを特定しそれから着⼿する 2. すべてのフィールド・パラメータ・返り値について「API 仕様ドキュメントの確認」 「実装コードのシグナル確認」を指⽰ 3. nullability 判定と根拠を表形式でユーザに提⽰し、承認を得る 4. @Nullable アノテーション付与 -> package-info.java を作成し @NullMarked 付与 5. ビルド & テスト (NullAway の警告もここでチェック。必要に応じて修正) 6. 利⽤者への影響を分析。対象モジュールの public API について以下が存在する場合は マイナーバージョンアップ & リリース周知の必要性を報告 a. メソッドの返り値、フィールドの getter の返り値が nullable に確定するケース b. メソッドのパラメータが non-null に確定するケース
© LY Corporation 実際やってみてわかってきたこと 26 • 依存ライブラリのドキュメントに nullability が明⽰されているかによって難易度が変わる •
API docs がないと、ライブラリの関数の返り値が null になりうるかどうかを ソースコードを読みにいって調べる必要が⽣じる • 当初は外部に露出する公開 API のみアノテーションを付与する⽅針も考えていたが、 結局ソースコード全体に付与するアプローチを採った • 公開 API のメソッドが内部 DTO を返り値に持つ場合が多く、結局それらの nullability を調査することになる • 公開 API に全て @NullMarked をつける / それ以外に @NullUnmarked をつけるの は⾯倒な上つけ忘れを招く • 外部から⾒えなくても、内部実装で NPE が⽣じるのを防げる
© LY Corporation 注意点 (1) 27 • Jackson でデシリアライズされるクラスについて。API 仕様上
null になり得ない ことを理由にフィールドを @NonNull に設定しておくと、NullAway に怒られる • 理由: NullAway はコンストラクタ終了時にすべての @NonNull フィールドが 初期化されているかを検査するため、setter 経由で後から値が⼊るフィールドに 対して偽陽性の警告が出る • 対処法: non-null フィールド初期化チェックをスキップするためにクラスに @SuppressWarnings(“NullAway.Init”) をつけるか、NullAway の設定 (-XepOpt:NullAway:ExternalInitAnnotations) を利⽤するのが良い https://github.com/uber/NullAway/wiki/Configuration
© LY Corporation 注意点 (2) 28 • JSR-305 annotation から移⾏する場合は
array のアノテーションに注意を! https://jspecify.dev/docs/using/#if-your-code-already-uses-jsr-305-annotations @Nullable Object[] • JSpecify で array ⾃体を nullable にしたいなら Object @Nullable [] とすべき。 @Nullable の直後に来たものが nullable になると覚えると良い JSR-305: 「array ⾃体が nullable」 JSpecify: 「nullable である object の array」
© LY Corporation 補⾜: アノテーションのつけ間違いに注意 29 • たまに外部ライブラリ側が JSpecify annotation
をつけ間違えていることが あり、利⽤者側で問題が発⽣ • nullable なものが誤って nonnull と指定され、Kotlin でのコンパイル エラーを招いた例 (reactor-core#4151) • 同様に Spring Security でも誤った nonnull 指定があり、NullAway の 偽陽性が発⽣したため patch (spring-security#19156) を提出するなど • つけ間違いは利⽤者に混乱を招くので注意を!
© LY Corporation この部分は どうやったらいいんだ? Platform Type の検出⽅法 04
© LY Corporation Platform Type の存在に気づくのは難しい 31 • IntelliJ IDEA
上で変数をホバーすれば Platform Type であることはわかるが、 特に Problem にも表⽰されないし、Qodana などの CLI ツールでも引っかからない • Kotlin のリンタである detekt には HasPlatformType というルールがあるが、これも Kotlin の公開 API に platform type が露出している場合しか検出してくれない • というわけで、Kotlin のソースコードの中に潜む Platform Type を検出する detekt のカスタムルールを⾃作しました • https://github.com/ternbusty/detekt-platform-type • detekt 2.0.0-alpha.3 に依存しており、あくまでも experimental なものです
© LY Corporation Platform Type はどうやって作られる? 32 Kotlin ソースコード (.kt)
PSI Program Structure Interface Kotlin Frontend Compiler FIR Frontend Intermediate Representation .class Java 関数の呼び出しがあった場合 Java の型を Kotlin に変換する処理を⾏う アノテーションがない場合は Platform Type となる IR Kotlin Backend Compiler 型の解決などが⾏われる
© LY Corporation Platform Type はどうやって作られる? 33 Kotlin ソースコード (.kt)
PSI Program Structure Interface Kotlin Frontend Compiler FIR Frontend Intermediate Representation .class IR Kotlin Backend Compiler detekt (Full Analysis Mode) PSI・FIR にアクセスし、 Platform Type を検出できる
© LY Corporation Rule 1: PlatformTypeAudit 34 • Platform Type
が検出され次第問答無⽤でアラートする Rule • Kotlin コード側で正しい null ハンドリングをしていても検出される • Kotlin のコード修正ではなく、依存先 Java レポジトリのアノテーション付与の必要性を 判断するためのものなので、Kotlin 側の CI 等で⽤いるのは避けた⽅が良い Platform Type を 検知してエラーに Kotlin 側で安全な ハンドルをしていても エラーになる仕様
© LY Corporation Rule 2: PlatformTypeUnhandled 35 • Platform Type
を正しくハンドリングしていない場合のみアラートする Rule • 検出した Platform Type のうち、正しくハンドルされておらず、NPE を引き起こす可能性が あるもののみ報告する • Kotlin 側のコードが、正しく Platform Type をハンドルできているかを知るための Rule なので、Kotlin 側の CI に⼊れても良い • 以下のように正しく handle しているものについては silence される val withFallback: String = javaClass.getNullableString() ?: "default" val safeStr: String? = javaClass.getNullableString() String? に格納している エルビス演算⼦を使って ハンドリング
© LY Corporation まとめ 36
© LY Corporation • 特にコンパイル時の挙動や実⾏時の挙動・ パフォーマンスに影響はなし • ただし、アプリケーション側でのメリット として、ライブラリ側が Null
を返すか 否かが明確になるので、 • JSpecify を解釈できる IDE で、 静的解析の性能が上がる • NullAway などの静的解析ツールを 導⼊していた場合、正確な結果が 出るようになる • Platform Type がなくなり、 null ハンド リングが必要な部分はコンパイル時に きちんとハンドリングが要求されるように なるのがメリット • 逆にハンドリングをしないと、 Kotlin 2.1 以降ではコンパイル エラーになるので注意 • エラーにならないようにコンパイル オプションで変えることはできるので、 アプリケーション側で即座の実装改修が 必要とされるわけではない Java Kotlin 37 結局 JSpecify アノテーションをつけるとどうなる?
© LY Corporation Take Home Message 38 • Java 側のコードにアノテーションを付与すると、Kotlin
側での Platform Type が 消え、Java ライブラリを安全に利⽤できるようになる • Kotlin だけでなく、そのライブラリを使う Java のアプリケーションにも恩恵がある • Spring Boot 4 時代なので JSpecify のアノテーションを使うべき • detekt カスタムルールを利⽤すれば、Java 側のアノテーション付与の必要性や、 Kotlin 側でのハンドリング不⾜が判定できる
© LY Corporation Thank You