Reputation: 143064
When creating a data class I frequently find that I want to transform one of the properties, usually to normalize it or to make a defensive copy. For example, here I want productCode
to always be lowercase:
data class Product(val productCode: String)
I've tried adding an init
block, in the hopes that Kotlin would be smart enough to let me manually deal with the assignment of the constructor parameter to the property:
data class Product(val productCode: String) {
init {
this.productCode = productCode.toLowerCase()
}
}
but it treats this as a reassignment.
I'd rather not have to write equals
/hashCode
/toString
/copy
by hand and IDE generated methods aren't really much better.
Is there any way to transform constructor parameters in a data class?
Upvotes: 16
Views: 3968
Reputation: 170713
What about
sealed class Product {
abstract val productCode: String
private data class Product(override val productCode: String) : your.package.Product()
companion object {
operator fun invoke(productCode: String): your.package.Product =
Product(productCode.toLowerCase())
}
}
All the advantages of data class
without exposing copy
. A negative is having to repeat property names an extra time.
Upvotes: 3
Reputation: 100358
No. For equality and toString to work, the properties need to be in the primary constructor.
What you can do however, is create a factory method:
data class Product private constructor(val productCode: String) {
companion object Factory {
fun create(productCode: String) : Product {
return Product(productCode.toLowerCase())
}
}
}
By making the constructor private
you force usage of this create
method.
If you want to get 'hacky', you can pretend you're still calling the constructor, by renaming create
to invoke
and making it an operator
function:
data class Product private constructor(val productCode: String) {
companion object {
operator fun invoke(productCode: String): Product {
return Product(productCode.toLowerCase())
}
}
}
Calling Product("foo")
will call the invoke
method.
Note: the constructor is still exposed through the copy
method, see https://youtrack.jetbrains.com/issue/KT-11914
Upvotes: 16