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
Kotlin2でdataクラスの copyメソッドを禁止する/Data class copy ...
Search
A1
October 23, 2024
Programming
1
830
Kotlin2でdataクラスの copyメソッドを禁止する/Data class copy function to have the same visibility as constructor
Server-Side Kotlin LT大会 vol.13 資料
A1
October 23, 2024
Tweet
Share
More Decks by A1
See All by A1
プロダクトのことは何でもNotebookLMに聞こう / NotebookLM for on boarding
eichisanden
2
110
短納期でローンチした新サービスをJavaで開発した話/launched new service using Java
eichisanden
6
4.1k
トラブルゼロで乗り切ったTypeScript移行/trouble-free TypeScript migration
eichisanden
3
3.5k
スクラム開発チームをLessでスケールさせた話/Scaling Scrum team with Less
eichisanden
0
5.9k
息の長いサービスのフロントエンドを少し改善する営み/frontend-improvement
eichisanden
3
2.9k
実はGitLabで使えるmermaid.js/gitlab-mermaid.js
eichisanden
1
740
既存 Web アプリケーションへの React.js 適用/react for web application
eichisanden
0
1.8k
楽楽明細でやってるChatOps/Development with ChatOps
eichisanden
0
1.2k
jshell概要
eichisanden
0
96
Other Decks in Programming
See All in Programming
AI時代に必須!状況言語化スキル / ai-context-verbalization
minodriven
2
360
Blazing Fast UI Development with Compose Hot Reload (Bangladesh KUG, October 2025)
zsmb
2
480
What's New in Web AI?
christianliebel
PRO
0
120
オンデバイスAIとXcode
ryodeveloper
0
420
contribution to astral-sh/uv
shunsock
0
590
外接に惑わされない自システムの処理時間SLIをOpenTelemetryで実現した話
kotaro7750
0
220
Nitro v3
kazupon
1
190
AsyncSequenceとAsyncStreamのプロポーザルを全部読む!!
s_shimotori
1
250
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
580
Eloquentを使ってどこまでコードの治安を保てるのか?を新人が考察してみた
itokoh0405
0
3.1k
NIKKEI Tech Talk#38
cipepser
0
420
ノーコードからの脱出 -地獄のデスロード- / Escape from Base44
keisuke69
0
640
Featured
See All Featured
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
Six Lessons from altMBA
skipperchong
29
4.1k
Testing 201, or: Great Expectations
jmmastey
46
7.8k
BBQ
matthewcrist
89
9.9k
Speed Design
sergeychernyshev
32
1.2k
Code Reviewing Like a Champion
maltzj
527
40k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.7k
Reflections from 52 weeks, 52 projects
jeffersonlam
355
21k
Agile that works and the tools we love
rasmusluckow
331
21k
Docker and Python
trallard
46
3.6k
Product Roadmaps are Hard
iamctodd
PRO
55
11k
Transcript
© 2024 Loglass Inc. 2024.10.25 三田 英一(@eichisanden) Kotlin2でdataクラスの copyメソッドを禁止する Server-Side
Kotlin LT大会 vol.13
© 2024 Loglass Inc. Profile 三田 英一 株式会社ログラス プロダクト開発部 エンジニア
株式会社ログラスに2024年5月に入社。 サーバーサイドはKotlin、フロントエンドは TypeScript+Reactで開発しています。 今まで様々な言語を使ってきましたが Kotlinは堅牢な型がありつつ書き味の良さもあって 1番好きな言語です。 Eiichi Mita
© 2024 Loglass Inc. Contents 1. Kotlin1.9まで 2. Kotlin2から 3.
先行して試す Contents
© 2024 Loglass Inc. Kotlin1.9まで Kotlin1.9まで dataクラスはequals, hashCodeなどを自動生成してくれて便利な反面、 コンストラクタの可視性に関わらず、publicなcopyメソッドを自動生成する問題 がありました。
© 2024 Loglass Inc. Kotlin1.9まで private constructorで外部からコンストラクタの使用を禁止し、Factoryメ ソッドでのインスタンス生成を強制したつもりでも... data class
PositiveInteger private constructor(val number: Int) { companion object { // 0より大きい値しか受け付けないFactoryメソッド fun create(number: Int): PositiveInteger? = if (number > 0) PositiveInteger(number) else null } } fun main() { val positiveNumber = PositiveInteger.create(42) ?: return }
© 2024 Loglass Inc. Kotlin1.9まで 自動生成されたcopyを呼べてしまう!不正なインスタンスを作り放題!! ドメイン層のインスタンスは不正な状態を作られたくないので、この抜け道は困る。 // マイナス値をセットできてしまう! val
negativeNumber = positiveNumber.copy(number = -1)
© 2024 Loglass Inc. Kotlin1.9まで 仕方ないので、意図しないところでcopyを呼び出さないようにArchUnitで チェックしていた。 @Test fun `ドメイン層のデータクラスに付属する
copyメソッドを呼び出すことはできない `() { val allApplicationClasses = ClassFileImporter() .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) .importPackages("com.example") methods() .should(BanDomainLayerDataClassCopyCondition) .check(allApplicationClasses) } private object BanDomainLayerDataClassCopyCondition : ArchCondition<JavaMethod>("data classのcopyは、同じクラス内でしかコールすることができない ") { override fun check(method: JavaMethod, events: ConditionEvents) { if (method.name != "copy\$default") return method.callsOfSelf.forEach { caller -> // this.copyは許容する if (method.owner != caller.originOwner) events.add(SimpleConditionEvent.violated(method,"エラーメッセージ ")) } } }
© 2024 Loglass Inc. Kotlin2から Kotlin2から dataクラスのcopyメソッドの可視性はプライマリコンストラクタと同じになる! いきなりではなく、段階的に実施される。
© 2024 Loglass Inc. タイムライン • フェーズ1: 2.0.20 ←今ここ ◦ 警告が表示されるようになった。
◦ @ConsistentCopyVisibilityで2.2以降の動作を先行してオプトイン可能。 ◦ @ExposedCopyVisibilityで明示的にcopyメソッドを公開可能。 • フェーズ2: 2.2(予定) ◦ 警告表示だった箇所がエラーに変わり、copyメソッドを呼び出せなくなる。 ◦ 互換性のためバイナリから消える訳ではない。 • フェーズ3: 2.3 or 2.4(予定) ◦ copyメソッドの可視性はプライマリコンストラクタと同じになる。 ◦ 役割を終えた@ConsistentCopyVisibilityは廃止される。 Kotlin2から
© 2024 Loglass Inc. 先行して試す Kotlin2.2まで時間があるので、 余裕を持って対応を終わらせておきたい。 (言うほど大変ではないと思いますが)
© 2024 Loglass Inc. 先行して試す @ConsistentCopyVisibilityを指定して2.2の動作をオプトインできる。 @ConsistentCopyVisibility data class PositiveInteger
private constructor(val number: Int) { companion object { fun create(number: Int): PositiveInteger? = if (number > 0) PositiveInteger(number) else null } } fun main() { val positiveNumber = PositiveInteger.create(42) ?: return val negativeNumber = positiveNumber.copy(number = -1) // Cannot access 'fun copy(number: Int = ...): PositiveInteger': it is private in '/PositiveInteger'. }
© 2024 Loglass Inc. 先行して試す アノテーションを個別のクラスに付与するのは現実的ではないので、コンパイラオプ ションで一括指定して、エラーになった箇所を少しずつ直すと良さそう。 // build.gradle.kts tasks
{ named("compileKotlin", KotlinCompilationTask::class.java) { compilerOptions { freeCompilerArgs.add("-Xconsistent-data-class-copy-visibility") } } }
© 2024 Loglass Inc. 先行して試す 明示的に許可したい場合は、@ExposedCopyVisibilityを付与することも可能。 @ExposedCopyVisibility data class PositiveInteger
private constructor(val number: Int) { companion object { fun create(number: Int): PositiveInteger? = if (number > 0) PositiveInteger(number) else null } } fun main() { val positiveNumber = PositiveInteger.create(42) ?: return // エラーにならない val negativeNumber = positiveNumber.copy(number = -1) }
© 2024 Loglass Inc. おわりに Kotlinは互換性や移行期間も考えてくれて 安心して使えると改めて感じました。
© 2024 Loglass Inc. おわりに Kotlin2に上げると 他にもビルドが早くなったり良いことがあるので バージョン上げてきましょう!!
© 2024 Loglass Inc.
© 2024 Loglass Inc. 参考URL • What's new in Kotlin
2.0.20 • [YouTrack]Confusing data class copy with private constructor • [Loglass Tech Blog Sprint] ArchUnitでKotlinのdata classのcopyメ ソッドを禁止する Appendix