Java中JAXB序列化java.util.Date默认调用toString(),应通过XmlAdapter自定义格式为ISO 8601;推荐改用Java 8时间API如LocalDateTime并配适配器,避免Date的线程安全以及时区问题。

Java中使用JAXB将java.util.Date序列化为XML时,默认行为往往不符合预期:它会调用Date.toString()生成类似Mon Jan 01 00:00:00 CST 2024的字符串,既不规范也不便于解析。正确做法是通过自定义适配器(XmlAdapter)统一控制格式,确保输出ISO 8601标准(如2024-01-01T00:00:00)或符合业务要求的时间格式。
使用XmlAdapter统一处理Date序列化
JAXB本身不直接支持java.util.Date的格式化,但允许通过@XmlJavaTypeAdapter绑定自定义转换逻辑。核心是继承XmlAdapter,在marshal()中将Date转为格式化字符串,在unmarshal()中反向解析。
- 创建适配器类,内部使用
SimpleDateFormat(注意线程安全,建议每次新建或使用ThreadLocal) - 在实体字段上添加
@XmlJavaTypeAdapter(DateAdapter.class) - 若需全局生效,可在
@XmlSchema或JAXBContext构建时注册,但字段级标注更清晰可控
推荐使用Java 8时间API替代Date(更健壮)
java.util.Date已属遗留类,JAXB原生不支持LocalDateTime、ZonedDateTime等,但可通过适配器轻松支持,且语义更明确、线程安全、无时区歧义。
- 例如用
LocalDateTimeAdapter配合DateTimeFormatter.ISO_LOCAL_DATE_TIME - 实体中改用
LocalDateTime字段,标注@XmlJavaTypeAdapter(LocalDateTimeAdapter.class) - 如需带时区,优先选
OffsetDateTime而非Date,避免系统默认时区干扰
避免常见陷阱
直接在Date字段上加@XmlSchemaType(name = "dateTime")无效——该注解仅对JAXB内置类型(如XMLGregorianCalendar)起作用;对Date无格式影响。
立即学习“Java免费学习笔记(深入)”;
- 不要在适配器中复用非线程安全的
SimpleDateFormat实例(尤其在Web容器中) - 反序列化时注意时区:
SimpleDateFormat默认按JVM时区解析,建议显式设setTimeZone(TimeZone.getTimeZone("UTC")) - 若服务需兼容旧客户端,可保留
Date字段但强制输出为UTC时间字符串,避免本地时区偏差
一个简洁可用的DateAdapter示例
以下适配器将Date序列化为yyyy-MM-dd'T'HH:mm:ss.SSS格式(毫秒级,无时区),适用于大多数内部系统交互:
public class DateAdapter extends XmlAdapter
private static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";
@Override
public String marshal(Date date) throws Exception {
if (date == null) return null;
return new SimpleDateFormat(PATTERN).format(date);
}
@Override
public Date unmarshal(String str) throws Exception {
if (str == null || str.trim().isEmpty()) return null;
return new SimpleDateFormat(PATTERN).parse(str);
}
}











