Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a builder for a Kotlin data class with many immutable properties

I have a Kotlin data class that I am constructing with many immutable properties, which are being fetched from separate SQL queries. If I want to construct the data class using the builder pattern, how do I do this without making those properties mutable?

For example, instead of constructing via

var data = MyData(val1, val2, val3)

I want to use

builder.someVal(val1)
// compute val2
builder.someOtherVal(val2)
// ... 
var data = builder.build()

while still using Kotlin's data class feature and immutable properties.

like image 339
Brian Voter Avatar asked Aug 06 '17 18:08

Brian Voter


2 Answers

I agree with the data copy block in Grzegorz answer, but it's essentially the same syntax as creating data classes with constructors. If you want to use that method and keep everything legible, you'll likely be computing everything beforehand and passing the values all together in the end.

To have something more like a builder, you may consider the following:

Let's say your data class is

data class Data(val text: String, val number: Int, val time: Long)

You can create a mutable builder version like so, with a build method to create the data class:

class Builder {
    var text = "hello"
    var number = 2
    var time = System.currentTimeMillis()

    internal fun build()
            = Data(text, number, time)

}

Along with a builder method like so:

fun createData(action: Builder.() -> Unit): Data {
    val builder = Builder()
    builder.action()
    return builder.build()
}

Action is a function from which you can modify the values directly, and createData will build it into a data class for you directly afterwards. This way, you can create a data class with:

val data: Data = createData {
    //execute stuff here
    text = "new text"
    //calculate number
    number = -1
    //calculate time
    time = 222L
}

There are no setter methods per say, but you can directly assign the mutable variables with your new values and call other methods within the builder.

You can also make use of kotlin's get and set by specifying your own functions for each variable so it can do more than set the field.

There's also no need for returning the current builder class, as you always have access to its variables.

Addition note: If you care, createData can be shortened to this:

fun createData(action: Builder.() -> Unit): Data = with(Builder()) { action(); build() }.

"With a new builder, apply our action and build"

like image 68
Allan W Avatar answered Sep 25 '22 18:09

Allan W


I don't think Kotlin has native builders. You can always compute all values and create the object at the end.

If you still want to use a builder you will have to implement it by yourself. Check this question

like image 44
Alberto S. Avatar answered Sep 21 '22 18:09

Alberto S.