@XmlJavaTypeAdapter 是 JAXB 处理日期格式最常用且推荐的方式,用于可控双向转换 java.util.Date、LocalDateTime 等类型与 XML 字符串,解决默认序列化兼容性问题。

Java JAXB 处理日期格式时,@XmlJavaTypeAdapter 是最常用且推荐的方式——它能将 java.util.Date、LocalDateTime、LocalDate 等类型与 XML 字符串之间做可控的双向转换,避免默认序列化(如毫秒时间戳或平台相关格式)带来的兼容性问题。
为什么需要 @XmlJavaTypeAdapter
JAXB 默认对 Date 类型使用 javax.xml.bind.DatatypeConverter,输出类似 2024-05-20T14:30:00.123+08:00 的 ISO 8601 格式;而对 LocalDateTime 等 Java 8 时间类则直接报错(不支持)。用 @XmlJavaTypeAdapter 可以:
- 统一指定输出格式(如
yyyy-MM-dd HH:mm:ss) - 适配不同时间类型(
LocalDateTime/LocalDate/ZonedDateTime) - 处理时区、空值、解析异常等边界情况
适配 LocalDateTime(推荐 Java 8+)
写一个自定义 Adapter:
public class LocalDateTimeAdapter extends XmlAdapter{ private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public LocalDateTime unmarshal(String s) throws Exception { if (s == null || s.trim().isEmpty()) return null; return LocalDateTime.parse(s.trim(), FORMATTER); } @Override public String marshal(LocalDateTime dateTime) throws Exception { return (dateTime == null) ? null : dateTime.format(FORMATTER); } }
在字段上使用:
立即学习“Java免费学习笔记(深入)”;
public class Order {
@XmlElement
@XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
private LocalDateTime createTime;
// getter/setter...
}
适配 Date(兼容老项目)
若仍用 java.util.Date,Adapter 可这样写:
public class DateAdapter extends XmlAdapter{ private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); static { FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+8")); } @Override public Date unmarshal(String s) throws Exception { if (s == null || s.trim().isEmpty()) return null; return FORMAT.parse(s.trim()); } @Override public String marshal(Date date) throws Exception { return (date == null) ? null : FORMAT.format(date); } }
注意:SimpleDateFormat 非线程安全,建议每个方法内新建实例,或用 ThreadLocal 封装(生产环境更稳妥)。
全局注册(避免重复标注)
如果多个类都用相同格式,可在 JAXBContext 创建时全局绑定:
Mapprops = new HashMap<>(); props.put("com.sun.xml.bind.defaultNamespacePrefix", "ns"); JAXBContext ctx = JAXBContext.newInstance(Order.class); // 注册全局 adapter(需配合 @XmlJavaTypeAdapters) // 或改用 Jakarta EE 方式:通过 package-info.java 声明
更简洁的方式是在包级声明 package-info.java:
@XmlJavaTypeAdapters({
@XmlJavaTypeAdapter(value = LocalDateTimeAdapter.class, type = LocalDateTime.class),
@XmlJavaTypeAdapter(value = DateAdapter.class, type = Date.class)
})
package com.example.model;
这样该包下所有字段自动生效,无需每个字段加注解。
基本上就这些。关键点是:选对时间类型、写好 Adapter 的 marshal/unmarshal 逻辑、注意线程安全和空值处理。不复杂但容易忽略细节。










