Reputation: 40520
I have a data class that looks like this:
data class MyDataCass(val x: String, val y: String,
val something: Something = Something(),
val somethingElse : SomethingElse = SomethingElse())
Since this class is going to be used from both Kotlin and Java I've also created a builder to make it easier to construct it from Java. The problem is that something
and somethingElse
are optional and I'd like to avoid duplication of the default values. This is essentially what I've tried:
data class MyDataCass(val x: String, val y: String,
val something: Something = Something(),
val somethingElse : SomethingElse = SomethingElse()) {
class Builder() {
private lateinit var x: String
private lateinit var y: String
private var something: Something? = null
private var somethingElse: SomethingElse? = null
// builder functions to set the properties defined above
...
fun build() = MyDataCass(x, y, something = ??, somethingElse = ??)
}
}
What I'd like to do is to set something
and somethingElse
only if they've been defined by the builder (i.e. they are not null
), otherwise I'd like to use the default values as defined by the data class constructor. I could of course change the build function to look like this:
fun build() = if (something == null && somethingElse == null) {
MyDataCass(x, y)
} else if(somethingElse == null) {
MyDataCass(x, y, something = something)
} else {
MyDataClass(x,y, somethingElse = somethingElse)
}
}
but I find this to be quite verbose and error prone. Is there a less verbose or more idiomatic way of achieving this?
Upvotes: 4
Views: 2324
Reputation: 89578
This is not supported very well by the language, if there was a good solution to this question that would help you too.
With that said, here's what I could come up with that lets you have the default values declared just once - at the cost of duplicating other code, however:
data class MyDataCass(val x: String, val y: String,
val something: Something,
val somethingElse: SomethingElse) {
companion object {
operator fun invoke(x: String, y: String,
something: Something? = null,
somethingElse: SomethingElse? = null) =
MyDataCass(x, y,
something ?: Something(),
somethingElse ?: SomethingElse())
}
class Builder {
private lateinit var x: String
private lateinit var y: String
private var something: Something? = null
private var somethingElse: SomethingElse? = null
// builder functions to set the properties defined above
// ...
fun build() = MyDataCass(x, y, something, somethingElse)
}
}
This way you can keep using the builder from Java, and in Kotlin the syntax that looks like is a call to the constructor is instead a call to the invoke
function of the companion object, which has the default values. Your data class of course still has non-nullable types so that it's easier to use.
Upvotes: 3