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

如何用Jackson编写自定义反序列化器兼容带/无时区时间数据?

实现Jackson兼容新旧时间格式的ZonedDateTime自定义反序列化器

核心思路

针对旧数据的数组格式[年,月,日,时,分,秒,纳秒],解析后结合预设时区生成ZonedDateTime;针对新数据的带时区格式,复用Jackson默认的反序列化逻辑,以此实现两种格式的兼容。

自定义反序列化器实现

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;

public class ZonedDateTimeCompatDeserializer extends StdDeserializer<ZonedDateTime> {

    // 旧数据的预设时区,根据实际场景修改
    private static final ZoneId DEFAULT_OLD_DATA_ZONE = ZoneId.of("+01:00");

    public ZonedDateTimeCompatDeserializer() {
        super(ZonedDateTime.class);
    }

    @Override
    public ZonedDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        JsonNode node = parser.getCodec().readTree(parser);

        // 处理旧格式:数组类型的时间数据
        if (node.isArray() && node.size() == 7) {
            int year = node.get(0).asInt();
            int month = node.get(1).asInt();
            int day = node.get(2).asInt();
            int hour = node.get(3).asInt();
            int minute = node.get(4).asInt();
            int second = node.get(5).asInt();
            int nano = node.get(6).asInt();

            LocalDateTime localDateTime = LocalDateTime.of(year, month, day, hour, minute, second)
                    .with(ChronoField.NANO_OF_SECOND, nano);
            return ZonedDateTime.of(localDateTime, DEFAULT_OLD_DATA_ZONE);
        }

        // 处理新格式:复用Jackson默认的ZonedDateTime反序列化逻辑
        return context.readValue(parser, ZonedDateTime.class);
    }
}

两种使用方式

1. 字段注解方式

直接在目标字段上添加@JsonDeserialize注解指定反序列化器:

public class DataFileRecord {
    @JsonDeserialize(using = ZonedDateTimeCompatDeserializer.class)
    private ZonedDateTime timeOfAcquisition;

    // getter、setter 方法省略
}

2. 全局注册方式

将反序列化器注册到ObjectMapper,全局生效:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class ObjectMapperConfig {
    public static ObjectMapper getConfiguredMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 注册JDK8时间类型支持模块
        objectMapper.registerModule(new JavaTimeModule());
        
        SimpleModule customModule = new SimpleModule();
        customModule.addDeserializer(ZonedDateTime.class, new ZonedDateTimeCompatDeserializer());
        objectMapper.registerModule(customModule);
        
        return objectMapper;
    }
}

注意事项

  • 必须引入Jackson的jackson-datatype-jsr310依赖,用于支持JDK8的时间类型(如ZonedDateTime)。
  • DEFAULT_OLD_DATA_ZONE需根据旧数据实际的生成时区调整,可使用时区ID(如"Europe/Paris")或偏移量(如"+02:00")。
  • 如果新数据的时区格式是自定义对象结构(而非标准ISO字符串),可在else分支中扩展解析逻辑,读取时区字段后构建ZonedDateTime。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:15:13