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

Gson序列化后Jackson反序列化java.sql.Timestamp报错解决方案

问题根因

报错本质是两端序列化规则不匹配:

  1. 默认Gson序列化java.sql.Timestamp类型时,会输出格式化的时间字符串,比如"2024-05-20 14:30:00.123"
  2. 你用Jackson把JSON解析为HashMap时,时间字段会被存为String类型;后续convertMapToEntity里的ObjectMapper没有配置String转java.sql.Timestamp的适配规则,无法直接把String转成Timestamp类型,就抛出参数非法异常。

所有调整都不能触碰三个约束:不能省略Gson序列化环节、不能修改convertMapToEntity方法、不能修改TestBean类,所以所有改动都落在main方法的可控代码范围内即可。

可行调整方案

以下方案均满足约束要求,按需选择即可:

  • 方案1:自定义Gson的Timestamp序列化规则,直接输出时间戳数值
    这是改动最小、兼容性最好的方案。给Gson注册类型适配器,把Timestamp序列化为long型的毫秒时间戳,后续Jackson转实体时,long值可以自动适配为java.sql.Timestamp类型,不需要额外做字符串解析,也不会有时区、时间格式不兼容的问题。
    替换原有Gson初始化代码即可:
    Gson gson = new GsonBuilder()
            .registerTypeAdapter(Timestamp.class, new TypeAdapter<Timestamp>() {
                @Override
                public void write(JsonWriter out, Timestamp value) throws IOException {
                    if (value == null) {
                        out.nullValue();
                        return;
                    }
                    out.value(value.getTime());
                }
    
                @Override
                public Timestamp read(JsonReader in) throws IOException {
                    if (in.peek() == JsonToken.NULL) {
                        in.nextNull();
                        return null;
                    }
                    return new Timestamp(in.nextLong());
                }
            }).create();
    
  • 方案2:调用转换方法前预处理Map,把时间字符串提前转为Timestamp对象
    因为convertMapToEntity方法不能改,你可以在拿到Jackson解析出的HashMap后,遍历字段把时间格式的字符串提前转为java.sql.Timestamp实例,再传入转换方法,此时内部ObjectMapper做同类型赋值就不会报错。
    参考实现:
    Map<String, Object> map = new ObjectMapper().readValue(jsonData, HashMap.class);
    // 预处理Map中的时间字段
    for (Map.Entry<String, Object> entry : map.entrySet()) {
        Object value = entry.getValue();
        if (!(value instanceof String timeStr)) {
            continue;
        }
        try {
            // 按Gson实际输出的时间字符串格式选择解析逻辑,默认toString格式直接用Timestamp.valueOf即可
            entry.setValue(Timestamp.valueOf(timeStr));
        } catch (IllegalArgumentException e) {
            // 非时间字段的字符串直接跳过
        }
    }
    TestBean abc = (TestBean) convertMapToEntity(map, TestBean.class);
    
  • 方案3:自定义main方法中ObjectMapper的反序列化规则
    你自己用来解析JSON为HashMap的ObjectMapper是可控的,可以给它注册Timestamp反序列化适配器,让它解析JSON时直接把时间字符串转为java.sql.Timestamp对象,而不是存为String,后续传入转换方法时类型直接匹配。
    参考配置:
    ObjectMapper customMapper = new ObjectMapper();
    SimpleModule tsModule = new SimpleModule()
            .addDeserializer(Timestamp.class, new JsonDeserializer<Timestamp>() {
                @Override
                public Timestamp deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                    String timeStr = p.getText();
                    // 匹配Gson输出的时间格式做解析即可
                    return Timestamp.valueOf(timeStr);
                }
            });
    customMapper.registerModule(tsModule);
    Map<String, Object> map = customMapper.readValue(jsonData, HashMap.class);
    
选型建议

优先选方案1,改动量最小,没有额外的字符串解析开销,跨服务传输数值型时间戳也不会因为服务端时区、时间格式配置差异出问题,稳定性最高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:09:30