如何将Kotlin数据类转换为Map并添加新键值对?
解决Kotlin数据类转Map并添加新键值对的问题
首先,你的核心需求是把嵌套的Kotlin数据类转换成可修改的Map,同时给每个DeviceGroup对应的Map添加devices键并填充数据。我们一步步来解决:
一、先解决数据类转Map的问题
Kotlin数据类没有内置的toMap()方法能处理嵌套结构(比如你的User里包含DeviceGroup集合,DeviceGroup又包含DeviceLink集合),所以我们有两种方案:
方案1:自己实现递归转换的扩展函数
这个方案适合不想引入第三方库的场景,我们写一个通用的扩展函数,递归处理所有嵌套的数据类和集合:
// 递归将任意数据类(及嵌套结构)转换为可修改的MutableMap fun Any.toMutableMap(): MutableMap<String, Any?> { val resultMap = mutableMapOf<String, Any?>() // 只处理数据类 if (this::class.isData) { this::class.memberProperties.forEach { property -> val value = property.get(this) resultMap[property.name] = when (value) { // 处理集合:把List/Set里的每个元素递归转Map,再转成可变集合 is Collection<*> -> value.map { item -> item?.toMutableMap() }.toMutableList() // 处理Map:键转成String,值递归转Map is Map<*, *> -> value.mapKeys { it.key.toString() } .mapValues { entry -> entry.value?.toMutableMap() } .toMutableMap() // 基本类型/非数据类直接存入 else -> value } } } else { // 非数据类(比如基本类型)的兜底处理 resultMap["value"] = this } return resultMap }
方案2:用Jackson库自动转换
如果你项目里已经用了Jackson(很多Spring项目都会用),直接用它的转换功能更省心,不用自己写递归逻辑:
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper // 初始化Jackson的Kotlin模块 val mapper = jacksonObjectMapper() // 把User对象直接转成MutableMap val response = mapper.convertValue(data, MutableMap::class.java) as MutableMap<String, Any?>
二、修改Map并添加新键值对
不管用哪种方案,我们得到的都是MutableMap(必须是可变的才能添加新键值对),接下来处理deviceGroup部分:
完整修正后的代码
fun main(request: HttpServletRequest) { val currentUser = request.session.getAttribute("user") as User val data = userRepository.findByName(currentUser.name) // 方案1:用自己写的扩展函数转成MutableMap val response = data.toMutableMap() // 方案2:用Jackson转(如果用这个就注释掉上面的方案1代码) // val mapper = jacksonObjectMapper() // val response = mapper.convertValue(data, MutableMap::class.java) as MutableMap<String, Any?> // 获取转换后的deviceGroup列表(注意类型是MutableList<MutableMap<String, Any?>>) val deviceGroups = response["deviceGroup"] as MutableList<MutableMap<String, Any?>> // 遍历每个deviceGroup的Map,添加devices键并填充数据 deviceGroups.forEach { deviceGroupMap -> // 从当前deviceGroup的Map里拿到名称 val groupName = deviceGroupMap["name"] as String // 从仓库获取完整的DeviceGroup(包含deviceLink数据) val fullDeviceGroup = deviceGroupRepository.findByName(groupName) // 把deviceLink里的Device转成Map,收集到Set中 val devicesSet = fullDeviceGroup.deviceLink.map { deviceLink -> deviceLink.device.toMutableMap() // 用同样的扩展函数转Device为Map }.toMutableSet() // 给当前deviceGroup的Map添加新的键值对 deviceGroupMap["devices"] = devicesSet } return response } // 如果你用方案1,需要把这个扩展函数加上 fun Any.toMutableMap(): MutableMap<String, Any?> { val resultMap = mutableMapOf<String, Any?>() if (this::class.isData) { this::class.memberProperties.forEach { property -> val value = property.get(this) resultMap[property.name] = when (value) { is Collection<*> -> value.map { item -> item?.toMutableMap() }.toMutableList() is Map<*, *> -> value.mapKeys { it.key.toString() } .mapValues { entry -> entry.value?.toMutableMap() } .toMutableMap() else -> value } } } else { resultMap["value"] = this } return resultMap }
修正了你代码里的几个错误
- 拼写错误:
deivceGroup改成了deviceGroup - Map没有
add方法:用deviceGroupMap["devices"] = devicesSet来添加新键值对 - 填充数据时的
this错误:应该取deviceLink.device来转成Map
三、最终效果
转换后的response结构会是这样:
{ "name": "test", "age": 17, "deviceGroup": [ { "name": "group1", "devices": [{"devId": xxx, "name": xxx}, ...] }, { "name": "group2", "devices": [{"devId": xxx, "name": xxx}, ...] } ] }
内容的提问来源于stack exchange,提问作者Funniest
相关产品推荐
相关产品推荐

