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

Jackson @JsonSerialize注解在Kotlin数据类新增属性时未生效

问题描述

我定义了两个Kotlin数据类Test1和Test2,二者的LocalDate类型date字段都添加了@JsonSerialize(using = ToStringSerializer::class)注解,Test2额外包含一个Duration类型的duration属性。

通过注册Kotlin模块与JavaTime模块的ObjectMapper进行序列化测试后发现:Test1的date字段正常序列化为字符串格式,而Test2的date字段被序列化为对象结构。当移除Test2的duration属性或将其类型改为String时,注解可正常生效。

相关代码

data class Test1(@JsonSerialize (using = ToStringSerializer::class) val date: LocalDate, val number: Int)
data class Test2(@JsonSerialize (using = ToStringSerializer::class) val date: LocalDate, val number: Int, val duration: Duration)

class SerializeTest {
    @Test
    fun test(){
        val mapper = ObjectMapper().apply{
            enable(SerializationFeature.INDENT_OUTPUT)
            registerModule(kotlinModule())
            registerModule(JavaTimeModule())
        }
        val x = Test1(Clock.System.todayAt(TimeZone.UTC), 123)
        val y = Test2(Clock.System.todayAt(TimeZone.UTC), 1, 1.seconds)

        println(mapper.writeValueAsString(x))
        println(mapper.writeValueAsString(y))
    }
}

(注:LocalDate和Duration为Kotlin类型,非Java类型)

序列化输出结果

{
  "date" : {
    "year" : 2022,
    "dayOfMonth" : 26,
    "month" : "DECEMBER",
    "dayOfWeek" : "MONDAY",
    "dayOfYear" : 360,
    "monthNumber" : 12,
    "value$kotlinx_datetime" : [ 2022, 12, 26 ]
  },
  "number" : 1,
  "duration" : 2000000000
}

{
  "date" : "2022-12-26",
  "number" : 123
}
原因分析

这个问题的核心是Jackson模块的序列化策略优先级冲突,具体逻辑如下:

  1. 你使用的LocalDate和Duration是kotlinx-datetime库的类型,而非Java原生java.time包下的类型,JavaTimeModule本身并不处理这类Kotlin专属时间类型。
  2. 对于Test1,由于没有特殊类型字段,Jackson会优先遵循字段上的@JsonSerialize注解,调用ToStringSerializer将LocalDate序列化为字符串。
  3. 当Test2包含Duration字段时,jackson-module-kotlin会触发针对整个类的默认序列化策略:它会优先通过Kotlin数据类的属性访问器序列化所有字段,直接忽略字段上的局部注解配置。这是因为模块在处理kotlinx-datetime.Duration这类未被其他模块覆盖的特殊类型时,会切换到更激进的默认序列化模式,覆盖了注解的优先级。
  4. 移除Duration字段或改为String类型后,类中不再存在需要特殊处理的类型,局部的@JsonSerialize注解会重新获得优先级,恢复正常工作。

解决建议

  • 替换JavaTimeModule为专门的kotlinx-datetime-jackson模块,它能正确处理所有kotlinx-datetime类型,同时尊重字段上的序列化注解。
  • 若必须保留现有模块配置,可以给Test2的date字段额外添加@JsonFormat(shape = JsonFormat.Shape.STRING)注解,强制Jackson将其序列化为字符串,覆盖默认策略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 12:50:53