XmlAdapter是JAXB提供的双向转换桥梁,用于解决自定义类型或Java 8时间类型等非标准类型与XML映射问题。它将Java对象转为可序列化的中间类型(如String),再转XML;反向同理。

什么是XmlAdapter,为什么需要它
JAXB 默认只能处理标准 Java 类型(如 String、Integer、LocalDateTime 等)与 XML 的映射。但实际开发中常遇到自定义类型(比如枚举封装类、带业务逻辑的值对象、第三方库类型),或希望用更简洁/兼容的 XML 格式(如把 LocalDateTime 序列化为 yyyy-MM-dd HH:mm:ss 字符串而非默认的复杂结构)。这时就需要 XmlAdapter —— 它是 JAXB 提供的双向转换桥梁:负责把 Java 对象转成可序列化的“中间类型”,再转成 XML;反向解析时也按此路径逆向还原。
写一个基础 XmlAdapter 示例(String ↔ 自定义 ID 类)
假设你有一个业务 ID 类 OrderId,只含一个 String 字段,但不希望 XML 直接暴露内部结构,而是像普通字符串一样扁平化处理:
// 自定义类型
public class OrderId {
private final String value;
public OrderId(String value) { this.value = value; }
public String getValue() { return value; }
// 必须有无参构造器(JAXB 反序列化需要)
private OrderId() { this(""); }
}
// 适配器:String ↔ OrderId
立即学习“Java免费学习笔记(深入)”;
public class OrderIdAdapter extends XmlAdapter{ @Override public OrderId unmarshal(String s) throws Exception { return s == null || s.trim().isEmpty() ? null : new OrderId(s); } @Override public String marshal(OrderId orderId) throws Exception { return orderId == null ? null : orderId.getValue(); } }
这个适配器声明了「XML 层用 String,Java 层用 OrderId」,JAXB 在序列化/反序列化时自动调用对应方法。
在实体类中使用 @XmlJavaTypeAdapter
有两种常用绑定方式:
- 字段级绑定:最常用,精准控制某字段
public class Order {
@XmlJavaTypeAdapter(OrderIdAdapter.class)
private OrderId id;
private String name;
// getter/setter...
}
-
包级绑定(package-info.java):适合全局统一规则,比如所有
LocalDateTime都用同一种格式
// src/main/java/com/example/model/package-info.java
@XmlJavaTypeAdapters({
@XmlJavaTypeAdapter(type = LocalDateTime.class, value = LocalDateTimeAdapter.class)
})
package com.example.model;
处理复杂类型:LocalDateTime 适配示例
Java 8 时间类型默认不被 JAXB 支持,需适配。注意:必须指定时区或明确使用「无时区语义」(如仅存日期时间字符串):
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 { return s == null ? null : LocalDateTime.parse(s, FORMATTER); } @Override public String marshal(LocalDateTime dt) throws Exception { return dt == null ? null : dt.format(FORMATTER); } }
使用时同样加注解即可。注意:若 XML 需要带时区(如 Z 或 +08:00),应改用 ZonedDateTime 或 OffsetDateTime 并调整格式器。
注意事项和常见坑
- 适配器类必须有无参构造器(JAXB 通过反射实例化)
-
unmarshal方法中不要抛未检查异常(Exception是受检异常,必须声明;若想抛RuntimeException,需包装后转为Exception再抛) - 如果适配的是集合元素类型(如
List),适配器仍作用于单个元素,无需额外处理集合 - 避免在
marshal/unmarshal中做重逻辑(如远程调用、数据库查询),保持轻量和纯函数特性 - 测试时建议同时验证序列化(
marshal)和反序列化(unmarshal)路径










