You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot中用Jackson将JSON键值转为User列表

问题场景

给定JSON数据:

{
  "USER0001": {
    "name": "hoge",
    "age": 20
  },
  "USER0002": {
    "name": "huga",
    "age": 10
  }
}

对应的Kotlin数据类:

data class User(
    val id: String,
    val name: String,
    val age: Int
)

期望在Spring控制器中,将上述JSON直接反序列化为List<User>:

listOf(
    User("USER0001", "hoge", 20),
    User("USER0002", "huga", 10),
)

当前控制器代码:

@RestController
class MyController() {
    fun test(@RequestBody users: List<User>) {
        // 期望直接使用users列表
    }
}

尝试自定义反序列化器但遇到问题:

class Deserializer : JsonDeserializer<List<User>>() {
    override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): List<User> {
        val treeNode = parser.codec.readTree<TreeNode>(parser)
        val fieldNames = treeNode.fieldNames()
        val result = mutableListOf<User>()
        
        while(fieldNames.hasNext()) {
            val fieldName = fieldNames.next()
            val userJson = treeNode.get(fieldName)
            // 不知道如何从userJson中提取值并构建User对象
        }
        
        return result
    }
}

解决方案

方法一:完善自定义JSON反序列化器

可以通过Jackson的API提取节点值,或者用ObjectMapper将节点转换为User对象,以下是完整实现:

import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.TreeNode
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.springframework.boot.jackson.JsonComponent

@JsonComponent // 自动注册到Spring Jackson配置
class UserListDeserializer : JsonDeserializer<List<User>>() {
    override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): List<User> {
        val treeNode = parser.codec.readTree<TreeNode>(parser)
        val result = mutableListOf<User>()
        val objectMapper = jacksonObjectMapper()
        
        val fieldNames = treeNode.fieldNames()
        while (fieldNames.hasNext()) {
            val userId = fieldNames.next()
            val userNode = treeNode.get(userId) as JsonNode
            
            // 方式1:手动提取字段值构建User
            val userName = userNode.get("name").asText()
            val userAge = userNode.get("age").asInt()
            result.add(User(userId, userName, userAge))
            
            // 方式2:用ObjectMapper转换节点为User,再补充id
            // val userWithoutId = objectMapper.treeToValue(userNode, User::class.java)
            // result.add(userWithoutId.copy(id = userId))
        }
        
        return result
    }
}

之后在控制器参数上指定使用该反序列化器:

@RestController
class MyController() {
    fun test(@RequestBody @JsonDeserialize(using = UserListDeserializer::class) users: List<User>) {
        // 正常使用users列表
    }
}

方法二:更简便的方式——接收Map再转List

无需自定义反序列化器,直接接收Map<String, User>后转换为目标列表:

@RestController
class MyController() {
    fun test(@RequestBody userMap: Map<String, User>) {
        val users = userMap.map { (id, user) -> user.copy(id = id) }
        // 使用users列表
    }
}

这种方式利用Jackson默认的Map反序列化能力,通过Kotlin的map函数快速转换,代码简洁易维护。


内容的提问来源于stack exchange,提问作者sho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 23:55:25