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

如何配置GSON识别ISO日期字符串并反序列化为Date对象?

解决Gson反序列化Map时自动识别日期字符串为Date对象的问题

要让Gson在反序列化Map<String, Object>时,自动将符合指定格式的字符串转换为Date对象,核心思路是自定义反序列化逻辑——默认情况下Gson处理Object类型时,只会将JSON字符串解析为String实例,不会主动尝试类型转换。以下是两种可行的实现方案:

方案一:自定义JsonDeserializer

通过实现JsonDeserializer<Object>,在反序列化时检查字符串是否匹配日期格式,符合条件则转换为Date:

1. 实现自定义反序列化器

import com.google.gson.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

public class DateAwareObjectDeserializer implements JsonDeserializer<Object> {
    // 匹配目标日期格式的正则
    private static final Pattern DATE_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z");
    // 对应日期格式解析器
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    @Override
    public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) {
            String strValue = json.getAsString();
            // 先通过正则过滤,避免无效解析尝试
            if (DATE_PATTERN.matcher(strValue).matches()) {
                try {
                    // SimpleDateFormat非线程安全,解析时需同步
                    synchronized (DATE_FORMAT) {
                        return DATE_FORMAT.parse(strValue);
                    }
                } catch (ParseException e) {
                    // 解析失败,返回原字符串
                    return strValue;
                }
            }
        }
        // 非目标类型或不匹配格式,交给Gson默认处理
        return context.deserialize(json, typeOfT);
    }
}

2. 注册并使用自定义反序列化器

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TestGson {
    public static void main(String[] args) {
        // 序列化测试
        Map<String, Object> originalMap = new HashMap<>();
        originalMap.put("now", new Date());

        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
                .registerTypeAdapter(Object.class, new DateAwareObjectDeserializer())
                .create();

        String json = gson.toJson(originalMap);
        System.out.println("序列化结果:" + json);

        // 反序列化测试
        Map<String, Object> deserializedMap = gson.fromJson(json, new TypeToken<Map<String, Object>>() {}.getType());
        Object nowValue = deserializedMap.get("now");
        System.out.println("反序列化后类型:" + nowValue.getClass());
        System.out.println("反序列化后值:" + nowValue);
    }
}

方案二:自定义TypeAdapter(性能更优)

TypeAdapter是Gson更底层的API,直接操作JsonReader/JsonWriter,避免了JsonElement的创建开销,性能更出色:

1. 实现自定义TypeAdapter

import com.google.gson.*;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

public class DateAwareObjectTypeAdapter extends TypeAdapter<Object> {
    private static final Pattern DATE_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z");
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    private final TypeAdapter<Object> delegateAdapter;

    public DateAwareObjectTypeAdapter(TypeAdapter<Object> delegateAdapter) {
        this.delegateAdapter = delegateAdapter;
    }

    @Override
    public void write(JsonWriter out, Object value) throws IOException {
        delegateAdapter.write(out, value);
    }

    @Override
    public Object read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        if (token == JsonToken.STRING) {
            String strValue = in.nextString();
            if (DATE_PATTERN.matcher(strValue).matches()) {
                try {
                    synchronized (DATE_FORMAT) {
                        return DATE_FORMAT.parse(strValue);
                    }
                } catch (ParseException e) {
                    return strValue;
                }
            }
            return strValue;
        }
        return delegateAdapter.read(in);
    }
}

2. 通过TypeAdapterFactory注册

Gson gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
        .registerTypeAdapterFactory(new TypeAdapterFactory() {
            @SuppressWarnings("unchecked")
            @Override
            public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
                if (type.getRawType() == Object.class) {
                    return (TypeAdapter<T>) new DateAwareObjectTypeAdapter(gson.getDelegateAdapter(this, type));
                }
                return null;
            }
        })
        .create();

关键说明

  1. 正则匹配的必要性:先用正则过滤字符串,避免对所有字符串执行日期解析,提升处理效率。
  2. 线程安全问题:SimpleDateFormat不是线程安全的,因此解析时必须加同步锁,或改用ThreadLocal存储每个线程独立的DateFormat实例。
  3. 多格式扩展:如果需要支持多种日期格式,可添加多个正则和DateFormat,依次尝试解析。
  4. 时区处理:原格式中的Z代表UTC时区,若需转换为本地时区,可通过DATE_FORMAT.setTimeZone(TimeZone.getDefault())调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 21:35:07