How to convert a Kotlin data class object to map?

耗尽温柔 提交于 2020-01-09 16:53:52

问题


Is there any easy way or any standard library method to convert a Kotlin data class object to a map/dictionary of it's properties by property names? Can reflection be avoided?


回答1:


I was using the jackson method, but turns out the performance of this is terrible on Android for first serialization (github issue here). And its dramatically worse for older android versions, (see benchmarks here)

But you can do this much faster with Gson. Conversion in both directions shown here:

val gson = Gson()

//convert a data class to a map
fun <T> T.serializeToMap(): Map<String, Any> {
    return convert()
}

//convert a map to a data class
inline fun <reified T> Map<String, Any>.toDataClass(): T {
    return convert()
}

//convert an object of type I to type O
inline fun <I, reified O> I.convert(): O {
    val json = gson.toJson(this)
    return gson.fromJson(json, object : TypeToken<O>() {}.type)
}



回答2:


I have the same use case today for testing and ended up i have used Jackson object mapper to convert Kotlin data class into Map. The runtime performance is not a big concern in my case. I haven't checked in details but I believe it's using reflection under the hood but it's out of concern as happened behind the scene.

For Example,

val dataclass = DataClass(p1 = 1, p2 = 2)
val dataclassAsMap = objectMapper.convertValue(dataclass, object: 
TypeReference<Map<String, Any>>() {})

//expect dataclassAsMap == mapOf("p1" to 1, "p2" to 2)



回答3:


This extension function uses reflection, but maybe it'll help someone like me coming across this in the future:

inline fun <reified T : Any> T.asMap() : Map<String, Any?> {
    val props = T::class.memberProperties.associateBy { it.name }
    return props.keys.associateWith { props[it]?.get(this) }
}



回答4:


The closest you can get is with delegated properties stored in a map.

Example (from link):

class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}

Using this with data classes may not work very well, however.




回答5:


Kpropmap is a reflection-based library that attempts to make working with Kotlin data classes and Maps easier. It has the following capabilities that are relevant:

  • Can transform maps to and from data classes, though note if all you need is converting from a data class to a Map, just use reflection directly as per @KenFehling's answer.
data class Foo(val a: Int, val b: Int)

// Data class to Map
val propMap = propMapOf(foo)

// Map to data class
val foo1 = propMap.deserialize<Foo>()
  • Can read and write Map data in a type-safe way by using the data class KProperty's for type information.

  • Given a data class and a Map, can do other neat things like detect changed values and extraneous Map keys that don't have corresponding data class properties.

  • Represent "partial" data classes (kind of like lenses). For example, say your backend model contains a Foo with 3 required immutable properties represented as vals. However, you want to provide an API to patch Foo instances. As it is a patch, the API consumer will only send the updated properties. The REST API layer for this obviously cannot deserialize directly to the Foo data class, but it can accept the patch as a Map. Use kpropmap to validate that the Map has the correct types, and apply the changes from the Map to a copy of the model instance:

data class Foo(val a: Int, val b: Int, val c: Int)

val f = Foo(1, 2, 3)
val p = propMapOf("b" to 5)

val f1 = p.applyProps(f) // f1 = Foo(1, 5, 3)

Disclaimer: I am the author.



来源:https://stackoverflow.com/questions/49860916/how-to-convert-a-kotlin-data-class-object-to-map

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!