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
250
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
短納期でローンチした新サービスをJavaで開発した話/launched new service using Java
eichisanden
6
3.8k
トラブルゼロで乗り切ったTypeScript移行/trouble-free TypeScript migration
eichisanden
3
3.2k
スクラム開発チームをLessでスケールさせた話/Scaling Scrum team with Less
eichisanden
0
5.4k
息の長いサービスのフロントエンドを少し改善する営み/frontend-improvement
eichisanden
3
2.6k
実はGitLabで使えるmermaid.js/gitlab-mermaid.js
eichisanden
1
550
既存 Web アプリケーションへの React.js 適用/react for web application
eichisanden
0
1.6k
楽楽明細でやってるChatOps/Development with ChatOps
eichisanden
0
1.1k
jshell概要
eichisanden
0
85
楽楽明細の開発を支える技術
eichisanden
0
590
Other Decks in Programming
See All in Programming
Jakarta EE meets AI
ivargrimstad
0
260
なまけものオバケたち -PHP 8.4 に入った新機能の紹介-
tanakahisateru
1
120
선언형 UI에서의 상태관리
l2hyunwoo
0
180
Security_for_introducing_eBPF
kentatada
0
110
Exploring: Partial and Independent Composables
blackbracken
0
100
短期間での新規プロダクト開発における「コスパの良い」Goのテスト戦略」 / kamakura.go
n3xem
2
170
return文におけるstd::moveについて
onihusube
1
1.1k
Stackless и stackful? Корутины и асинхронность в Go
lamodatech
0
820
Haze - Real time background blurring
chrisbanes
1
510
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
490
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
830
今年のアップデートで振り返るCDKセキュリティのシフトレフト/2024-cdk-security-shift-left
tomoki10
0
210
Featured
See All Featured
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
48
2.2k
Designing Experiences People Love
moore
138
23k
Testing 201, or: Great Expectations
jmmastey
40
7.1k
Visualization
eitanlees
146
15k
Unsuck your backbone
ammeep
669
57k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
2k
Become a Pro
speakerdeck
PRO
26
5k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
810
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.9k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
127
18k
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