Hessian 4.0.65 支持 JDK8 时间类型序列化/反序列化

文章来源原创   作者:临窗旋墨   发布时间:2025-08-25   阅读:44   标签:架构,代码规范 分类:我的编码 专题:编码随手记

Hessian 4.0.65 支持 JDK8 时间类型序列化/反序列化

源码地址:/lcxm-common - JavaTimeSerializerFactory

20250825

背景

Hessian 4.0.65 默认不支持 JDK 8 时间类型 (LocalDateLocalDateTimeLocalTime) 的序列化/反序列化。原始实现使用单独的 SerializerFactory,重复代码多,不支持泛型对象,也不方便扩展其他时间类型。


改进方案:JavaTimeSerializerFactory

统一工厂 JavaTimeSerializerFactory,特性:

  • 默认支持:LocalDateLocalDateTimeLocalTimeOffsetDateTimeZonedDateTimeYearMonth
  • 可扩展注册其他时间类型
  • 支持对象和泛型对象中的时间类型
  • 缓存 SerializerDeserializer,提高性能

核心设计

1. JavaTimeHandler<T>

封装时间类型的解析和格式化逻辑:

  1. public class JavaTimeHandler<T> {
  2. final Class<T> type;
  3. final DateTimeFormatter formatter;
  4. final Function<String, T> parser;
  5. final Function<T, String> formatterFunc;
  6. public JavaTimeHandler(Class<T> type,
  7. DateTimeFormatter formatter,
  8. Function<String, T> parser,
  9. Function<T, String> formatterFunc) { ... }
  10. public String format(Object obj) { return formatterFunc.apply(type.cast(obj)); }
  11. public T parse(String str) { return parser.apply(str); }
  12. }

2. JavaTimeSerializer<T>

序列化为 Hessian Map 结构:

  1. public class JavaTimeSerializer<T> extends AbstractSerializer {
  2. private static final String KEY = "_value";
  3. private final JavaTimeHandler<T> handler;
  4. public JavaTimeSerializer(JavaTimeHandler<T> handler) { this.handler = handler; }
  5. @Override
  6. public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
  7. String dateStr = handler.format(obj);
  8. out.writeMapBegin(handler.type.getName());
  9. out.writeString(KEY);
  10. out.writeString(dateStr);
  11. out.writeMapEnd();
  12. }
  13. }

3. JavaTimeDeserializer<T>

反序列化 Hessian Map 为时间对象:

  1. public class JavaTimeDeserializer<T> extends AbstractDeserializer {
  2. private static final String KEY = "_value";
  3. private final JavaTimeHandler<T> handler;
  4. public JavaTimeDeserializer(JavaTimeHandler<T> handler) { this.handler = handler; }
  5. @Override
  6. public Object readMap(AbstractHessianInput in) throws IOException {
  7. String dateStr = null;
  8. while (!in.isEnd()) {
  9. String key = in.readString();
  10. if (KEY.equals(key)) {
  11. dateStr = in.readString();
  12. } else {
  13. in.readObject();
  14. }
  15. }
  16. in.readMapEnd();
  17. return dateStr == null ? null : handler.parse(dateStr);
  18. }
  19. @Override
  20. public Class<?> getType() { return handler.type; }
  21. }

4. JavaTimeSerializerFactory

统一管理 JDK8 时间类型的 Hessian 序列化逻辑:

  1. public class JavaTimeSerializerFactory extends AbstractSerializerFactory {
  2. private static final JavaTimeSerializerFactory instance = new JavaTimeSerializerFactory();
  3. public static JavaTimeSerializerFactory getInstance() { return instance; }
  4. private final Map<Class<?>, JavaTimeHandler<?>> handlers = new HashMap<>();
  5. private final Map<Class<?>, Serializer> serializerCache = new HashMap<>();
  6. private final Map<Class<?>, Deserializer> deserializerCache = new HashMap<>();
  7. private JavaTimeSerializerFactory() { registerDefaults(); }
  8. private void registerDefaults() {
  9. // LocalDate
  10. register(LocalDate.class, DateTimeFormatter.ISO_LOCAL_DATE,
  11. str -> LocalDate.parse(str, DateTimeFormatter.ISO_LOCAL_DATE),
  12. date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE));
  13. // LocalDateTime
  14. register(LocalDateTime.class, DateTimeFormatter.ISO_LOCAL_DATE_TIME,
  15. str -> LocalDateTime.parse(str, DateTimeFormatter.ISO_LOCAL_DATE_TIME),
  16. dt -> dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
  17. // LocalTime
  18. register(LocalTime.class, DateTimeFormatter.ISO_LOCAL_TIME,
  19. str -> LocalTime.parse(str, DateTimeFormatter.ISO_LOCAL_TIME),
  20. t -> t.format(DateTimeFormatter.ISO_LOCAL_TIME));
  21. // OffsetDateTime
  22. register(OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME,
  23. str -> OffsetDateTime.parse(str, DateTimeFormatter.ISO_OFFSET_DATE_TIME),
  24. dt -> dt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
  25. // ZonedDateTime
  26. register(ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME,
  27. str -> ZonedDateTime.parse(str, DateTimeFormatter.ISO_ZONED_DATE_TIME),
  28. dt -> dt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
  29. // YearMonth
  30. register(YearMonth.class, DateTimeFormatter.ofPattern("yyyy-MM"),
  31. str -> YearMonth.parse(str, DateTimeFormatter.ofPattern("yyyy-MM")),
  32. ym -> ym.format(DateTimeFormatter.ofPattern("yyyy-MM")));
  33. }
  34. public <T> void register(Class<T> clazz,
  35. DateTimeFormatter formatter,
  36. Function<String, T> parser,
  37. Function<T, String> formatterFunc) {
  38. handlers.put(clazz, new JavaTimeHandler<>(clazz, formatter, parser, formatterFunc));
  39. }
  40. @Override
  41. public Serializer getSerializer(Class cl) {
  42. return serializerCache.computeIfAbsent(cl, c -> {
  43. JavaTimeHandler<?> handler = handlers.get(c);
  44. return handler != null ? new JavaTimeSerializer<>(handler) : null;
  45. });
  46. }
  47. @Override
  48. public Deserializer getDeserializer(Class cl) {
  49. return deserializerCache.computeIfAbsent(cl, c -> {
  50. JavaTimeHandler<?> handler = handlers.get(c);
  51. return handler != null ? new JavaTimeDeserializer<>(handler) : null;
  52. });
  53. }
  54. }

Hessian2Serializer 工具类

封装 Hessian 序列化/反序列化逻辑:

  1. public class Hessian2Serializer implements XqdSerializer {
  2. public static final SerializerFactory serializerFactory = SerializerFactory.createDefault();
  3. static {
  4. serializerFactory.addFactory(JavaTimeSerializerFactory.getInstance());
  5. }
  6. @Override
  7. public <T> byte[] serialize(T obj) {
  8. try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
  9. Hessian2Output out = new Hessian2Output(os);
  10. out.setSerializerFactory(serializerFactory);
  11. out.writeObject(obj);
  12. out.flush();
  13. return os.toByteArray();
  14. } catch (Exception e) {
  15. throw new CommonException("Hessian2 序列化失败", e);
  16. }
  17. }
  18. @Override
  19. public <T> T deserialize(byte[] data, Class<T> clazz) {
  20. try (ByteArrayInputStream is = new ByteArrayInputStream(data)) {
  21. Hessian2Input in = new Hessian2Input(is);
  22. in.setSerializerFactory(serializerFactory);
  23. return (T) in.readObject(clazz);
  24. } catch (Exception e) {
  25. throw new CommonException("Hessian2 反序列化失败", e);
  26. }
  27. }
  28. @Override
  29. public boolean selfDescribed() { return true; }
  30. }

使用示例

测试单个 LocalDate

  1. LocalDate date = LocalDate.now();
  2. byte[] bytes = serializer.serialize(date);
  3. LocalDate result = serializer.deserialize(bytes, LocalDate.class);
  4. System.out.println(result);

测试对象包含 LocalDate

  1. TestModel model = new TestModel();
  2. model.setDate(LocalDate.now());
  3. byte[] bytes = serializer.serialize(model);
  4. TestModel result = serializer.deserialize(bytes, TestModel.class);
  5. System.out.println(result.getDate());

测试泛型对象 XqdResponse

  1. XqdResponse<LocalDate> resp = XqdResponse.success(LocalDate.now());
  2. byte[] bytes = serializer.serialize(resp);
  3. XqdResponse result = serializer.deserialize(bytes, XqdResponse.class);
  4. System.out.println(result.getData());

序列化/反序列化流程

序列化流程:

  • LocalDate(2025-08-25) →
  • Hessian 流 = {type:”java.time.LocalDate”, “_value”:”2025-08-25”}

反序列化流程:

  • Hessian 读到 type=java.time.LocalDate → 找到 LocalDateDeserializer
  • 数据结构是 map → 调用 readMap()
  • 在 readMap() 里拿到 “_value” -> “2025-08-25” → 返回 LocalDate.parse(“2025-08-25”)

优点

  • 支持 JDK8 日期类型:LocalDateLocalDateTimeLocalTimeOffsetDateTimeZonedDateTimeYearMonth
  • 支持对象和泛型对象
  • 可扩展注册新类型
  • 缓存序列化器/反序列化器,提高性能
  • 命名清晰、结构整洁

注意事项

  • 避免使用旧的 LocalDateSerializerFactoryLocalDateTimeSerializerFactory
  • 可通过 JavaTimeSerializerFactory.register() 扩展新类型
  • 使用 Hessian2Serializer 时确保已注册工厂

发表评论

目录