Gson序列化后Jackson反序列化java.sql.Timestamp报错解决方案
问题根因
报错本质是两端序列化规则不匹配:
- 默认Gson序列化
java.sql.Timestamp类型时,会输出格式化的时间字符串,比如"2024-05-20 14:30:00.123" - 你用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
相关产品推荐
相关产品推荐

