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
780
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
1
95
短納期でローンチした新サービスをJavaで開発した話/launched new service using Java
eichisanden
6
4k
トラブルゼロで乗り切ったTypeScript移行/trouble-free TypeScript migration
eichisanden
3
3.5k
スクラム開発チームをLessでスケールさせた話/Scaling Scrum team with Less
eichisanden
0
5.8k
息の長いサービスのフロントエンドを少し改善する営み/frontend-improvement
eichisanden
3
2.9k
実はGitLabで使えるmermaid.js/gitlab-mermaid.js
eichisanden
1
720
既存 Web アプリケーションへの React.js 適用/react for web application
eichisanden
0
1.8k
楽楽明細でやってるChatOps/Development with ChatOps
eichisanden
0
1.2k
jshell概要
eichisanden
0
95
Other Decks in Programming
See All in Programming
メモリ不足との戦い〜大量データを扱うアプリでの実践例〜
kwzr
1
740
Web技術を最大限活用してRAW画像を現像する / Developing RAW Images on the Web
ssssota
2
1.1k
プログラマのための作曲入門
cheebow
0
520
iOSアプリの信頼性を向上させる取り組み/ios-app-improve-reliability
shino8rayu9
0
140
Conquering Massive Traffic Spikes in Ruby Applications with Pitchfork
riseshia
0
140
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
310
XP, Testing and ninja testing ZOZ5
m_seki
2
220
Reduxモダナイズ 〜コードのモダン化を通して、将来のライブラリ移行に備える〜
pvcresin
2
670
開発生産性を上げるための生成AI活用術
starfish719
1
130
気づいて!アプリからのSOS 〜App Store Connect APIで始めるパフォーマンス健康診断〜
waka12
0
260
Introducing ReActionView: A new ActionView-Compatible ERB Engine @ Kaigi on Rails 2025, Tokyo, Japan
marcoroth
3
860
CI_CD「健康診断」のススメ。現場でのボトルネック特定から、健康診断を通じた組織的な改善手法
teamlab
PRO
0
160
Featured
See All Featured
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.2k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
GitHub's CSS Performance
jonrohan
1032
460k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.4k
Building Adaptive Systems
keathley
43
2.8k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
23
1.5k
Learning to Love Humans: Emotional Interface Design
aarron
274
40k
4 Signs Your Business is Dying
shpigford
185
22k
Navigating Team Friction
lara
189
15k
Making Projects Easy
brettharned
118
6.4k
How STYLIGHT went responsive
nonsquared
100
5.8k
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