Hessian 4.0.65 支持 JDK8 时间类型序列化/反序列化
20250825
背景
Hessian 4.0.65 默认不支持 JDK 8 时间类型 (LocalDate、LocalDateTime、LocalTime) 的序列化/反序列化。原始实现使用单独的 SerializerFactory,重复代码多,不支持泛型对象,也不方便扩展其他时间类型。
改进方案:JavaTimeSerializerFactory
统一工厂 JavaTimeSerializerFactory,特性:
- 默认支持:
LocalDate、LocalDateTime、LocalTime、OffsetDateTime、ZonedDateTime、YearMonth - 可扩展注册其他时间类型
- 支持对象和泛型对象中的时间类型
- 缓存
Serializer和Deserializer,提高性能
核心设计
1. JavaTimeHandler
封装时间类型的解析和格式化逻辑:
public class JavaTimeHandler<T> {
final Class<T> type;
final DateTimeFormatter formatter;
final Function<String, T> parser;
final Function<T, String> formatterFunc;
public JavaTimeHandler(Class<T> type,
DateTimeFormatter formatter,
Function<String, T> parser,
Function<T, String> formatterFunc) { ... }
public String format(Object obj) { return formatterFunc.apply(type.cast(obj)); }
public T parse(String str) { return parser.apply(str); }
}
2. JavaTimeSerializer
序列化为 Hessian Map 结构:
public class JavaTimeSerializer<T> extends AbstractSerializer {
private static final String KEY = "_value";
private final JavaTimeHandler<T> handler;
public JavaTimeSerializer(JavaTimeHandler<T> handler) { this.handler = handler; }
@Override
public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
String dateStr = handler.format(obj);
out.writeMapBegin(handler.type.getName());
out.writeString(KEY);
out.writeString(dateStr);
out.writeMapEnd();
}
}
3. JavaTimeDeserializer
反序列化 Hessian Map 为时间对象:
public class JavaTimeDeserializer<T> extends AbstractDeserializer {
private static final String KEY = "_value";
private final JavaTimeHandler<T> handler;
public JavaTimeDeserializer(JavaTimeHandler<T> handler) { this.handler = handler; }
@Override
public Object readMap(AbstractHessianInput in) throws IOException {
String dateStr = null;
while (!in.isEnd()) {
String key = in.readString();
if (KEY.equals(key)) {
dateStr = in.readString();
} else {
in.readObject();
}
}
in.readMapEnd();
return dateStr == null ? null : handler.parse(dateStr);
}
@Override
public Class<?> getType() { return handler.type; }
}
4. JavaTimeSerializerFactory
统一管理 JDK8 时间类型的 Hessian 序列化逻辑:
public class JavaTimeSerializerFactory extends AbstractSerializerFactory {
private static final JavaTimeSerializerFactory instance = new JavaTimeSerializerFactory();
public static JavaTimeSerializerFactory getInstance() { return instance; }
private final Map<Class<?>, JavaTimeHandler<?>> handlers = new HashMap<>();
private final Map<Class<?>, Serializer> serializerCache = new HashMap<>();
private final Map<Class<?>, Deserializer> deserializerCache = new HashMap<>();
private JavaTimeSerializerFactory() { registerDefaults(); }
private void registerDefaults() {
// LocalDate
register(LocalDate.class, DateTimeFormatter.ISO_LOCAL_DATE,
str -> LocalDate.parse(str, DateTimeFormatter.ISO_LOCAL_DATE),
date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE));
// LocalDateTime
register(LocalDateTime.class, DateTimeFormatter.ISO_LOCAL_DATE_TIME,
str -> LocalDateTime.parse(str, DateTimeFormatter.ISO_LOCAL_DATE_TIME),
dt -> dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// LocalTime
register(LocalTime.class, DateTimeFormatter.ISO_LOCAL_TIME,
str -> LocalTime.parse(str, DateTimeFormatter.ISO_LOCAL_TIME),
t -> t.format(DateTimeFormatter.ISO_LOCAL_TIME));
// OffsetDateTime
register(OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME,
str -> OffsetDateTime.parse(str, DateTimeFormatter.ISO_OFFSET_DATE_TIME),
dt -> dt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
// ZonedDateTime
register(ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME,
str -> ZonedDateTime.parse(str, DateTimeFormatter.ISO_ZONED_DATE_TIME),
dt -> dt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// YearMonth
register(YearMonth.class, DateTimeFormatter.ofPattern("yyyy-MM"),
str -> YearMonth.parse(str, DateTimeFormatter.ofPattern("yyyy-MM")),
ym -> ym.format(DateTimeFormatter.ofPattern("yyyy-MM")));
}
public <T> void register(Class<T> clazz,
DateTimeFormatter formatter,
Function<String, T> parser,
Function<T, String> formatterFunc) {
handlers.put(clazz, new JavaTimeHandler<>(clazz, formatter, parser, formatterFunc));
}
@Override
public Serializer getSerializer(Class cl) {
return serializerCache.computeIfAbsent(cl, c -> {
JavaTimeHandler<?> handler = handlers.get(c);
return handler != null ? new JavaTimeSerializer<>(handler) : null;
});
}
@Override
public Deserializer getDeserializer(Class cl) {
return deserializerCache.computeIfAbsent(cl, c -> {
JavaTimeHandler<?> handler = handlers.get(c);
return handler != null ? new JavaTimeDeserializer<>(handler) : null;
});
}
}
Hessian2Serializer 工具类
封装 Hessian 序列化/反序列化逻辑:
public class Hessian2Serializer implements XqdSerializer {
public static final SerializerFactory serializerFactory = SerializerFactory.createDefault();
static {
serializerFactory.addFactory(JavaTimeSerializerFactory.getInstance());
}
@Override
public <T> byte[] serialize(T obj) {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
Hessian2Output out = new Hessian2Output(os);
out.setSerializerFactory(serializerFactory);
out.writeObject(obj);
out.flush();
return os.toByteArray();
} catch (Exception e) {
throw new CommonException("Hessian2 序列化失败", e);
}
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) {
try (ByteArrayInputStream is = new ByteArrayInputStream(data)) {
Hessian2Input in = new Hessian2Input(is);
in.setSerializerFactory(serializerFactory);
return (T) in.readObject(clazz);
} catch (Exception e) {
throw new CommonException("Hessian2 反序列化失败", e);
}
}
@Override
public boolean selfDescribed() { return true; }
}
使用示例
测试单个 LocalDate
LocalDate date = LocalDate.now();
byte[] bytes = serializer.serialize(date);
LocalDate result = serializer.deserialize(bytes, LocalDate.class);
System.out.println(result);
测试对象包含 LocalDate
TestModel model = new TestModel();
model.setDate(LocalDate.now());
byte[] bytes = serializer.serialize(model);
TestModel result = serializer.deserialize(bytes, TestModel.class);
System.out.println(result.getDate());
测试泛型对象 XqdResponse
XqdResponse<LocalDate> resp = XqdResponse.success(LocalDate.now());
byte[] bytes = serializer.serialize(resp);
XqdResponse result = serializer.deserialize(bytes, XqdResponse.class);
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 日期类型:
LocalDate、LocalDateTime、LocalTime、OffsetDateTime、ZonedDateTime、YearMonth - 支持对象和泛型对象
- 可扩展注册新类型
- 缓存序列化器/反序列化器,提高性能
- 命名清晰、结构整洁
注意事项
- 避免使用旧的
LocalDateSerializerFactory和LocalDateTimeSerializerFactory - 可通过
JavaTimeSerializerFactory.register()扩展新类型 - 使用 Hessian2Serializer 时确保已注册工厂
GitHub 登录
Gitee 登录
QQ 登录