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

Jackson序列化Duration格式不统一,如何强制全部序列化为字符串

问题说明

使用Jackson进行序列化时遇到java.time.Duration类型序列化结果不一致的问题:当Duration作为Map的键时被序列化为ISO-8601字符串格式,作为普通对象属性时被序列化为秒级双精度格式。

复现代码
record MyObject(@JsonProperty("duration") Duration duration) {
}

@Test
public void testJackson() throws JsonProcessingException {
    var map = Map.of(Duration.ofHours(1), new MyObject(Duration.ofHours(1)));
    ObjectMapper om = new ObjectMapper();
    om.registerModule(new JavaTimeModule());
    var json = om.writerWithDefaultPrettyPrinter().writeValueAsString(map);
    System.out.println(json);
}
实际输出
{
  "PT1H" : {
    "duration" : 3600.000000000
  }
}
已尝试方案

尝试通过自定义DurationSerializer重写useTimestamp方法返回false,并为属性添加@JsonSerialize(using = MyDurationSerializer.class)注解解决问题,方案未生效。
自定义序列化器代码:

public class MyDurationSerializer extends DurationSerializer {

    @Override
    protected boolean useTimestamp(SerializerProvider provider) {
        return false;
    }
}
解决方案

该问题由Jackson默认序列化特性导致:JavaTimeModule默认开启SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS,会将作为值的Duration序列化为秒级时间戳,而Map键的序列化不受该特性影响,默认调用toString()方法输出ISO-8601格式字符串。

不需要自定义序列化器,直接全局关闭对应序列化特性即可实现全局统一效果,所有Duration类型都会序列化为字符串格式:

ObjectMapper om = new ObjectMapper();
om.registerModule(new JavaTimeModule());
// 新增行关闭Duration序列化为时间戳的特性
om.disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS);

修改后运行测试代码,输出结果为:

{
  "PT1H" : {
    "duration" : "PT1H"
  }
}

如果确实需要使用自定义序列化器,需要将其注册到全局的JavaTimeModule中,而非仅通过注解单独配置属性,才能覆盖全局默认逻辑:

JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(Duration.class, new MyDurationSerializer());
om.registerModule(javaTimeModule);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 02:36:02