seata1.4.1版本下
在使用mysql驱动8.0时,seata在进行undo日志处理时,JacksonUndoLogParser发生了反序列化报错。
具体错误信息如下
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"nano":356806000,"month":"APRIL","dayOfWeek":"MONDAY","dayOfYear":102,"year":2021,"monthValue":4,"dayOfMonth":12,"hour":9,"minute":31,"second":39,"chronology":{"calendarType":"iso8601","id":"ISO"}}"; line: 1, column: 2]
原因是: 数据库类型datetime在mysql8.0会被映射为LocalDateTime类型【具体映射可查看com.mysql.jdbc.ResultSetImpl.getObject()方法】,在序列化保存到数据库后使用jackson无法反序列化
查看JacksonUndoLogParser源码后发现仅增加Timestamp类的序列化和反序列化处理,对LocalDateTime的序列化和反序列化未做处理
private final ObjectMapper mapper = new ObjectMapper();
private final SimpleModule module = new SimpleModule();
public void init() {
module.addSerializer(Timestamp.class, timestampSerializer);
module.addDeserializer(Timestamp.class, timestampDeserializer);
module.addSerializer(SerialBlob.class, blobSerializer);
module.addDeserializer(SerialBlob.class, blobDeserializer);
module.addSerializer(SerialClob.class, clobSerializer);
module.addDeserializer(SerialClob.class, clobDeserializer);
mapper.registerModule(module);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
mapper.enable(MapperFeature.PROPAGATE_TRANSIENT_MARKER);
}
查看GitHub后发现已有人提出类似的问题,并且有人已经提交PR并合并到develop分支了,目前已经合并到1.4.2分支处理了。
项目中seata版本升级到1.4.2后,新建 JsonDateTimeSerializer 类
public class JsonDateTimeSerializer implements JacksonSerializer<LocalDateTime> {
private static final DateTimeFormatter DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public Class<LocalDateTime> type() {
return LocalDateTime.class;
}
@Override
public JsonSerializer<LocalDateTime> ser() {
return new LocalDateTimeSerializer(DATETIME_FORMAT);
}
@Override
public JsonDeserializer<? extends LocalDateTime> deser() {
return new LocalDateTimeDeserializer(DATETIME_FORMAT);
}
}
然后在 resources 目录下新建 seata/io.seata.rm.datasource.undo.parser.spi.JacksonSerializer 文件
文件内填入 JsonDateTimeSerializer 类的完整路径。
com.xxx.seata.jackson.JsonDateTimeSerializer
至此就支持 LocalDateTime 的序列化和反序列化了
————————————————
原文链接:https://blog.csdn.net/zh0134/article/details/115612416