如何将Kotlin数据类对象转换为映射?

时间:2018-04-16 15:22:50

标签: object dictionary kotlin

是否有任何简单的方法或任何标准库方法通过属性名称将Kotlin数据类对象转换为其属性的地图/字典?可以避免反思吗?

8 个答案:

答案 0 :(得分:6)

我今天有相同的用例进行测试,最后我使用了Jackson对象映射器将Kotlin数据类转换为Map。在我的案例中,运行时性能不是一个大问题。我还没有详细检查过,但我相信它会在引擎盖下使用反射,但它不会出现在幕后发生的事情。

例如,

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)

答案 1 :(得分:2)

此扩展功能使用了反射功能,但它可能会帮助像我这样的人将来遇到这个问题:

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) }
}

答案 2 :(得分:1)

您最接近的是delegated properties stored in a map

示例(来自链接):

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

然而,将此与数据类一起使用可能效果不佳。

答案 3 :(得分:1)

kotlinx.serialization 具有实验性的 Properties 格式,可以非常轻松地将 Kotlin 类转换为地图,反之亦然:

@ExperimentalSerializationApi
@kotlinx.serialization.Serializable
data class Category constructor(
    val id: Int,
    val name: String,
    val icon: String,
    val numItems: Long
) {

    // the map representation of this class
    val asMap: Map<String, Any> by lazy { Properties.encodeToMap(this) }

    companion object {
        // factory to create Category from a map
        fun from(map: Map<String, Any>): Category =
            Properties.decodeFromMap(map)
    }
}

答案 4 :(得分:0)

我使用的是jackson方法,但事实证明,在Android上进行首次序列化(github issue here)时,此方法的性能很差。对于旧版android(see benchmarks here

但是您可以使用Gson更快地完成此操作。双向转换如下所示:

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)
}

答案 5 :(得分:0)

Kpropmap是一个基于反射的库,试图简化Kotlin数据类和Maps的使用。它具有以下相关功能:

  • 可以转换地图tofrom的数据类,但是请注意,如果您需要的只是从数据类转换为Map,只需按照@KenFehling的答案直接使用反射。
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>()
  • 可以通过使用数据类Map获取类型信息来在type-safe way中读写KProperty数据。

  • 给定一个数据类和一个Map,可以do other neat things来检测更改的值和没有相应数据类属性的无关的Map键。

  • 代表“部分”数据类(类似于lenses)。例如,假设您的后端模型包含一个Foo,其中3个必需的不可变属性表示为val。但是,您想提供一个API来修补Foo实例。由于是补丁程序,因此API使用者将仅发送更新的属性。显然,用于此的REST API层不能直接反序列化到Foo数据类,但是可以将修补程序作为Map接受。使用kpropmap验证Map是否具有正确的类型,并使用Map的{​​{3}}到模型实例的副本:

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)

免责声明:我是作者。

答案 6 :(得分:0)

@汤姆·汉利

我在以下代码中尝试了您的解决方案:

package tmp

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

// https://stackoverflow.com/questions/49860916/how-to-convert-a-kotlin-data-class-object-to-map
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)
}

fun main() {
  //example usage
  data class Person(val name: String, val age: Int)

  val person = Person("Tom Hanley", 99)

  val map = mapOf(
    "name" to "Tom Hanley",
    "age" to 99
  )

  val personAsMap: Map<String, Any> = person.serializeToMap()
  println(personAsMap)

  val mapAsPerson: Person = map.toDataClass()
  println(mapAsPerson)
}

执行后,我在控制台中看到两个空值。我使用Kotlin 1.4和Gson 2.8.6。我对Kotlin并不陌生,也许我在某个地方出错了。

答案 7 :(得分:0)

我尝试序列化数据类 Person,然后将其反序列化为 Map 以读取其值。

 val props: Map<String, String> = objectMapper.readValue(
                objectMapper.writeValueAsString(person))