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
相关产品推荐
相关产品推荐

