繁体   English   中英

将 Map 转换为数据 Class

[英]Convert a Map to a Data Class

Kotlin 中是否有简单的方法允许我将 Map 转换为任意数据 class?

我正在尝试转换的 Map 具有数据 class 所需字段的所有键。

我四处寻找,但没能找到任何似乎以非常通用的方式谈论这样做的东西。

我知道我可以使用ObjectMapper ,但这需要一个额外的库。 寻找 Kotlin 可用的东西。

为什么不只使用地图委托?

class MyData(val map: Map<String, String>) {
    val foo by map
    val bar by map
}

或者您可以使用伴随对象包装它并使用MyData.from(mymap)调用它

data class MyData(val foo: String, val bar: String) {
    companion object {
        fun from(map: Map<String, String>) = object {
            val foo by map
            val bar by map

            val data = MyData(foo, bar)
        }.data
    }

也许委托属性适合您。 这样你也可以只调整地图。 然而,这也允许添加不能 1:1 映射到您的类属性的键和值,例如:

class YourData { 
  val backedMap = mutableMapOf<String, String>()
  var someProp by backedMap
}

val obj = YourData().apply {
    someProp = "value"
}

现在,如果backedMap可见,则还可以添加以下内容,即使不存在任何此类属性:

obj.backedMap["unknown prop"] = "some other value"

另一方面,同样的地图可用于自动填写您的字段:

val sourceMap = mutableMapOf("someProp" to "newValue") // the map you want to use to automatically fill up your data class
sourceMap.forEach { key, newValue -> obj.backedMap[key] = newValue }

另一种方法是“只是”使用反射。 这样你就可以省略支持映射,而只是扫描属性,例如:

YourData::class.memberProperties.asSequence()
                                .filterIsInstance<KMutableProperty<*>>()
                                .filter { it.name in sourceMap.keys }
                                .forEach { prop ->
                                  prop.setter.call(obj, sourceMap[prop.name])
                                }

使用 kotlin 反射将构造函数参数映射到映射值,此通用函数适用于在主构造函数中接收字段数据的任何类

与 Firebase 等 JSON 数据库配合良好,并使用 Firebase DocumentSnapshot.data 中的 Map 对象进行了测试

fun <T : Any> mapToObject(map: Map<String, Any>, clazz: KClass<T>) : T {
    //Get default constructor
    val constructor = clazz.constructors.first()
    
    //Map constructor parameters to map values
    val args = constructor
    .parameters
    .map { it to map.get(it.name) }
    .toMap()
   
    //return object from constructor call
    return constructor.callBy(args)
}

有一些课

data class Person(val firs: String, val last: String)

像这样使用

mapToObject(map, Person::class)

虽然这来晚了,但它可能会帮助像它这样的人帮助我。

我查看了@killjoy 的评论,我立即感到震惊,因为我的诚实回答一直在我的腿上。

答:使用任何 Json 库,例如 GSON() 或 JSon Kotlin 序列化库,都可以解决这个问题。

这是一个通用示例:

    allUploadsLiveData.observe(viewLifecycleOwner, {
        val userUploads = ((it.value as HashMap<*, *>).values.toList())
        for (upload in userUploads){
            val product = ((upload as HashMap<*, *>).values.toList()[0] as HashMap<*, *>)
            
            // Use Gson() to convert to Json format 
            val json = Gson().toJson(product)
            try {
                //Use Gson() to convert to Your custom class. For me here is ProductData
                val data = Gson().fromJson(json, ProductData::class.java)
                println("This is all the new data *********************************** ${data.productImageUrl}")
            } catch (e: Exception){
                println("Exception *************** $${e.printStackTrace()}")
            }
        }
    })

不要忘记添加 Gson() 依赖项版本 2.9.0 是我此时回复的最新版本。 替换谷歌最多的版本 rest Gson

implementation "com.google.code.gson:gson:2.8.8"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM