Kotlinのdata class
はコンストラクタをprivate
にしたとしても、copy
メソッドはprivate
にならずに使用可能でした。そのため問題が起きることがありました。2.0.20
からはこの問題に対応することができます。
これまで
例えば、以下のようなdata class
があったとします。
data class User private constructor(
val name: String,
val age: Int
) {
companion object {
fun create(name: String, age: Int): User {
require(age in 0..200)
return User(name, age)
}
}
}
コンストラクタはprivate
にしています。
このdata class
を使用するときに、copy
メソッドはprivate
になっていないため、以下のようなことが可能です。
val user = User.create(name = "Test", age = 20)
// copyメソッドが使えてしまう
val newUser = user.copy(age = -1)
copy
メソッドが使えてしまうため、ファクトリメソッドで制限などをしていても不正な状態が作れてしまいます。
2.0.20から
警告表示
2.0.20
からdata class
のprivate
コンストラクタを使ってると、ビルド時に警告が表示されるようになります。
w: <path_to>/Main.kt:3:17 Non-public primary constructor is exposed via the generated 'copy()' method of the 'data' class.
The generated 'copy()' will change its visibility in future releases.
To suppress the warning do one of the following:
- Annotate the data class with the '@ConsistentCopyVisibility' annotation.
- Use the '-Xconsistent-data-class-copy-visibility' compiler flag.
- Annotate the data class with the '@ExposedCopyVisibility' annotation
(Discouraged, but can be used to keep binary compatibility).
To learn more, see the documentation of the '@ConsistentCopyVisibility' and '@ExposedCopyVisibility' annotations.
This will become an error in Kotlin 2.1.
w: <path_to>/Main.kt:17:20 This 'copy()' exposes the non-public primary constructor of a 'data class'. Please migrate the usage. See the appropriate 'data class' documentation or contact the 'data class' author for migration guidance. This will become an error in Kotlin 2.1.
将来的にcopy
メソッドの可視性が変更されることを説明しています。
アノテーションを使ったOpt In
@ConsistentCopyVisibility
を使うことで警告ではなくエラーにすることができます。
@ConsistentCopyVisibility // <- Opt-In
data class User private constructor(
val name: String,
val age: Int
) {
// ...
}
このアノテーションをつけたdata class
ではcopy
メソッドがprivate
になるため、ビルドエラーになります。
compiler flagでのOpt In
すべてdata class
でOpt inしたい場合はcompiler flagを設定することで、対応できます。 -Xconsistent-data-class-copy-visibility
を使います。
tasks.named("compileKotlin", org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask::class.java) {
compilerOptions {
freeCompilerArgs.add("-Xconsistent-data-class-copy-visibility")
}
}
逆にcompiler flagでOpt inした場合に特定のdata class
は除外したい場合は、 @ExposedCopyVisibility
をつけると除外できます。
@ExposedCopyVisibility // <- copyメソッドが使えるようになる
data class User private constructor(
val name: String,
val age: Int
) {
// ...
}
今後
https://youtrack.jetbrains.com/issue/KT-11914
こちらのYouTrackに記載されています。
- 2.0.20では警告が表示。compiler flag等でエラーにすることができる。
- 2.1 or 2.2では警告がエラーになりますが、バイナリは互換性の問題からpublicで生成される。
- 2.2 or 2.3ではエラーになる。compiler flag等は不要になる。