是否有任何简单的方法或任何标准库方法通过属性名称将Kotlin数据类对象转换为其属性的地图/字典?可以避免反思吗?
答案 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的使用。它具有以下相关功能:
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))