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?
A Kotlin data class must have a primary constructor that defines at least one member. Other than that, you can add secondary constructors as explained in Classes and Inheritance - Secondary Constructors.
Constructor Kotlin data class. The compiler generates the utility methods based on the declaration of the primary constructor. For the data class to work as expected, your data classes have to fulfill the below requirements: The primary constructor with at least one parameter.
Answer: Kotlin provides a special type of class called data class, which is usually used for objects that act as a store for data properties and has no business logic or member functions. It provides a lot of advantages with reduced boilerplate code.
You can't override getter in kotlin data class with error of Data class primary constructor must have only property (val/ var) parameters . While you can do so in a regular class.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With