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

Spring Boot中Kotlin Jackson嵌套JSON反序列化报错问题

Kotlin Jackson反序列化嵌套JSON的类型转换错误解决办法

问题背景

在Spring Boot中用Jackson反序列化嵌套JSON到Kotlin数据类时,遇到报错:

Cannot construct instance of ...C (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('test')

对应的JSON结构:

{
   "values":[
      {
         "name":"test",
         "map":{
            "d1":"d1Value",
            "d2":"d2Value",
            "d3":"d3Value"
         }
      },
      {
         "name":"test1",
         "map":{
            "d1":"d1Value",
            "d4":"d4Value"
         }
      }
   ]
}

使用的Kotlin数据类:

data class A(
    val values: List<B>,
)

data class B(
    val name: C,
    val map: Map<D, String>,
)

data class C(@JsonValue val value: String)
data class D(@JsonValue val value: String)

问题原因

@JsonValue注解仅用于序列化时将对象转为字符串,但反序列化时,Jackson不知道如何从字符串实例化C、D这类数据类——Kotlin数据类的主构造器默认不会被Jackson自动识别为反序列化的构造逻辑入口。

解决方法

方法1:给数据类添加@JsonCreator注解

直接在C、D的主构造器上标注@JsonCreator,告诉Jackson用这个构造器从字符串创建实例:

data class A(
    val values: List<B>,
)

data class B(
    val name: C,
    val map: Map<D, String>,
)

// 给主构造器添加@JsonCreator
data class C @JsonCreator constructor(@JsonValue val value: String)
data class D @JsonCreator constructor(@JsonValue val value: String)

方法2:用伴生对象的工厂方法配合@JsonCreator

如果不想修改主构造器,可以在伴生对象里写工厂方法,并用@JsonCreator标记:

data class C(@JsonValue val value: String) {
    companion object {
        @JsonCreator
        fun fromString(value: String): C = C(value)
    }
}

data class D(@JsonValue val value: String) {
    companion object {
        @JsonCreator
        fun fromString(value: String): D = D(value)
    }
}

方法3:确保Jackson Kotlin模块正确注册

Spring Boot通常会自动注册Kotlin模块,但如果是手动创建ObjectMapper,需要显式添加模块,让Jackson能识别Kotlin数据类的构造参数:

val mapper = jacksonObjectMapper().registerModule(KotlinModule.Builder().build())
val a = mapper.readValue<A>(json)

或者在Spring配置中自定义ObjectMapper:

@Configuration
class JacksonConfig {
    @Bean
    fun objectMapper(): ObjectMapper {
        return ObjectMapper().registerModule(KotlinModule())
    }
}

验证示例

修正后运行反序列化代码,即可正常解析JSON:

val json = """
{
   "values":[
      {
         "name":"test",
         "map":{
            "d1":"d1Value",
            "d2":"d2Value",
            "d3":"d3Value"
         }
      },
      {
         "name":"test1",
         "map":{
            "d1":"d1Value",
            "d4":"d4Value"
         }
      }
   ]
}
""".trimIndent()

val mapper = jacksonObjectMapper().registerModule(KotlinModule())
val result = mapper.readValue<A>(json)
println(result)

内容的提问来源于stack exchange,提问作者J.Doe

相关产品推荐
方舟 Agent Plan

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

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