Matthias
Matthias

Reputation: 31

Map Key Values to Dataclass in Kotlin

how can I set properties of a dataclass by its name. For example, I have a raw HTTP GET response

propA=valueA
propB=valueB

and a data class in Kotlin

data class Test(var propA: String = "", var propB: String = ""){}

in my code i have an function that splits the response to a key value array

val test: Test = Test()
rawResp?.split('\n')?.forEach { item: String ->
    run {
         val keyValue = item.split('=')
         TODO
    }
}

In JavaScript I can do the following

response.split('\n').forEach(item => {
    let keyValue = item.split('=');
    this.test[keyValue[0]] = keyValue[1];
 });

Is there a similar way in Kotlin?

Upvotes: 0

Views: 3849

Answers (2)

Juan Rada
Juan Rada

Reputation: 3766

By the question, it was not clear for me if each line represents a Test instance or not. So

If not.

fun parse(rawResp: String): Test = rawResp.split("\n").flatMap { it.split("=") }.let { Test(it[0], it[1]) }

If yes.

fun parse(rawResp: String): List<Test> = rawResp.split("\n").map { it.split("=") }.map { Test(it[0], it[1]) }

For null safe alternative you can use nullableString.orEmpty()...

Upvotes: 1

ysakhno
ysakhno

Reputation: 863

You cannot readily do this in Kotlin the same way you would in JavaScript (unless you are prepared to handle reflection yourself), but there is a possibility of using a Kotlin feature called Delegated Properties (particularly, a use case Storing Properties in a Map of that feature).

Here is an example specific to code in your original question:

class Test(private val map: Map<String, String>) {
    val propA: String by map
    val propB: String by map

    override fun toString() = "${javaClass.simpleName}(propA=$propA,propB=$propB)"
}

fun main() {
    val rawResp: String? = """
        propA=valueA
        propB=valueB
        """.trimIndent()

    val props = rawResp?.split('\n')?.map { item ->
        val (key, value) = item.split('=')
        key to value
    }?.toMap() ?: emptyMap()

    val test = Test(props)

    println("Property 'propA' of test is: ${test.propA}")
    println("Or using toString: $test")
}

This outputs:

Property 'propA' of test is: valueA
Or using toString: Test(propA=valueA,propB=valueB)

Unfortunately, you cannot use data classes with property delegation the way you would expect, so you have to 'pay the price' and define the overridden methods (toString, equals, hashCode) on your own if you need them.

Upvotes: 1

Related Questions