mardi 28 janvier 2020

Deep merging data classes in Kotlin

How can I do a recursive / deep merge of two data classes in Kotlin? Something like this:

import kotlin.reflect.*
import kotlin.reflect.full.*

data class Address(
  val street: String? = null,
  val zip: String? = null
)

data class User(
  val name: String? = null,
  val age: Int? = null,
  val address: Address? = null
)

inline fun <reified T : Any> T.merge(other: T): T {
  val nameToProperty = T::class.declaredMemberProperties.associateBy { it.name }
  val primaryConstructor = T::class.primaryConstructor!!
  val args = primaryConstructor.parameters.associate { parameter ->
    val property = nameToProperty[parameter.name]!!
    val type = property.returnType.classifier as KClass<*>
    if (type.isData) {
      parameter to this.merge(other) //inline function can't be recursive
    } else {
      parameter to (property.get(other) ?: property.get(this))
    }
  }
  return primaryConstructor.callBy(args)
}

val u1 = User(name = "Tiina", address = Address(street = "Hämeenkatu"))
val u2 = User(age = 23, address = Address(zip = "33100"))

u1.merge(u2)
// expected: User(age = 23, name= "Tiina", address = Address(zip = "33100", street = "Hämeenkatu")

related: Combining/merging data classes in Kotlin





Aucun commentaire:

Enregistrer un commentaire