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
980
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
130
短納期でローンチした新サービスをJavaで開発した話/launched new service using Java
eichisanden
6
4.2k
トラブルゼロで乗り切ったTypeScript移行/trouble-free TypeScript migration
eichisanden
3
3.6k
スクラム開発チームをLessでスケールさせた話/Scaling Scrum team with Less
eichisanden
0
6.2k
息の長いサービスのフロントエンドを少し改善する営み/frontend-improvement
eichisanden
3
3k
実はGitLabで使えるmermaid.js/gitlab-mermaid.js
eichisanden
1
810
既存 Web アプリケーションへの React.js 適用/react for web application
eichisanden
0
1.9k
楽楽明細でやってるChatOps/Development with ChatOps
eichisanden
0
1.2k
jshell概要
eichisanden
0
110
Other Decks in Programming
See All in Programming
Goの型安全性で実現する複数プロダクトの権限管理
ishikawa_pro
2
1.4k
CS教育のDX AIによる育成の効率化
niftycorp
PRO
0
170
テレメトリーシグナルが導くパフォーマンス最適化 / Performance Optimization Driven by Telemetry Signals
seike460
PRO
2
180
モダンOBSプラグイン開発
umireon
0
180
夢の無限スパゲッティ製造機 -実装篇- #phpstudy
o0h
PRO
0
160
PHPで TLSのプロトコルを実装してみる
higaki_program
0
520
脱 雰囲気実装!AgentCoreを良い感じにWEBアプリケーションに組み込むために
takuyay0ne
3
410
モックわからないマン卒業記 ~振る舞いを起点に見直した、フロントエンドテストにおけるモックの使いどころ~
tasukuwatanabe
3
430
AI時代のシステム設計:ドメインモデルで変更しやすさを守る設計戦略
masuda220
PRO
6
1.1k
最初からAWS CDKで技術検証してもいいんじゃない?
akihisaikeda
4
180
野球解説AI Agentを開発してみた - 2026/02/27 LayerX社内LT会資料
shinyorke
PRO
0
370
CSC307 Lecture 15
javiergs
PRO
0
270
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
330
40k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.2k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.5k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
1
160
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
130
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
490
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
How to build a perfect <img>
jonoalderson
1
5.3k
Agile that works and the tools we love
rasmusluckow
331
21k
The agentic SEO stack - context over prompts
schlessera
0
720
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
64
53k
How GitHub (no longer) Works
holman
316
150k
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