WebFlux GET请求反序列化嵌套Map<String,Map<String,String>>报错如何解决
问题原因
报错的本质是Jackson反序列化时无法正确识别嵌套泛型的类型约束,错误将内层Map的值反序列化为LinkedHashMap对象,后续尝试强转为String时触发类型转换异常,大多数情况下是Kotlin环境下ParameterizedTypeReference匿名类的泛型信息丢失导致的。
解决方案
方案1:使用Kotlin reified泛型扩展(优先推荐,无需自定义序列化)
Spring WebFlux对Kotlin提供了带reified泛型的bodyToMono扩展方法,可以自动保留完整的嵌套泛型类型信息,避免手动声明ParameterizedTypeReference导致的类型擦除问题:
suspend fun getProperties(): Map<String, Map<String, String>> { return webClient .get() .uri("/property/all") .retrieve() // 直接使用带泛型的扩展方法,无需手动创建ParameterizedTypeReference .bodyToMono<Map<String, Map<String, String>>>() .awaitSingle() }
需确保项目已引入以下依赖:
org.springframework.boot:spring-boot-starter-webflux(Spring Boot项目默认包含)com.fasterxml.jackson.module:jackson-module-kotlin:Jackson对Kotlin的适配模块,可解决大部分Kotlin泛型反序列化问题
方案2:自定义嵌套Map反序列化器
如果方案1仍无法解决问题,可以自定义反序列化器强制指定嵌套结构的类型解析逻辑:
步骤1:编写自定义反序列化器
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonDeserializer import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.node.ObjectNode class NestedStringMapDeserializer : JsonDeserializer<Map<String, Map<String, String>>>() { override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Map<String, Map<String, String>> { val rootNode = p.codec.readTree<JsonNode>(p) as ObjectNode val result = mutableMapOf<String, Map<String, String>>() // 遍历外层Map键值对 rootNode.fields().forEach { (outerKey, innerNode) -> val innerMap = mutableMapOf<String, String>() // 遍历内层节点,强制将所有值转换为String类型 innerNode.fields().forEach { (innerKey, valueNode) -> innerMap[innerKey] = valueNode.asText() } result[outerKey] = innerMap } return result } }
步骤2:注册反序列化器到WebClient
import com.fasterxml.jackson.databind.module.SimpleModule import org.springframework.http.codec.json.Jackson2JsonDecoder import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.KotlinModule // 构造自定义ObjectMapper并注册反序列化器 val customObjectMapper = jacksonObjectMapper() .registerModule(KotlinModule.Builder().build()) .registerModule(SimpleModule().apply { addDeserializer(object : com.fasterxml.jackson.core.type.TypeReference<Map<String, Map<String, String>>>() {}, NestedStringMapDeserializer() ) }) // 用自定义ObjectMapper构造WebClient实例 val webClient = WebClient.builder() .baseUrl("你的服务基础地址") .codecs { configurer -> configurer.defaultCodecs().jackson2JsonDecoder(Jackson2JsonDecoder(customObjectMapper)) } .build()
如果是Spring Boot项目,也可以将包含自定义反序列化器的SimpleModule注册为Spring Bean,全局自动生效。
内容的提问来源于stack exchange,提问作者user994612
相关产品推荐
相关产品推荐

