| 註解 | 作用對象 | 核心屬性 | 說明 |
@XmlRootElement | Class | name, namespace | 映射 XML 根元素,缺省類名 |
@XmlType | Class | propOrder, name, namespace | 定義 XML Schema 類型與字段輸出順序 |
@XmlAccessorType(XmlAccessType.FIELD) | Class | FIELD/PROPERTY/PUBLIC_MEMBER/NONE | FIELD:直接綁定非 static/transient 字段(推薦,無需 getter) |
@XmlElement | Field/Getter | name, required, nillable, defaultValue | 映射 XML 子元素 |
@XmlAttribute | Field/Getter | name, required | 映射 XML 屬性 |
@XmlElementWrapper | Collection/Array | name, nillable | 為集合生成外層包裝元素(如 <employees><employee/></employees>) |
@XmlJavaTypeAdapter | Field/Class/Package | value (extends XmlAdapter) | 自定義序列化邏輯(如 LocalDate 格式化) |
@XmlTransient | Field/Getter | - | 忽略該字段,不參與綁定 |
完整實戰示例
1. 實體類定義
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "employee")
@XmlType(propOrder = {"name", "age", "role", "gender"})
public class Employee {
@XmlAttribute(name = "id") // 映射為屬性
private Long id;
@XmlElement(name = "fullName") // 映射為元素,自定義名稱
private String name;
private int age;
private String role;
private String gender;
// getter/setter/toString 省略...
}
2. XML 樣例
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee id="1">
<fullName>Pankaj</fullName>
<age>29</age>
<role>Java Developer</role>
<gender>Male</gender>
</employee>
3. 雙向轉換工具類
public class JaxbUtils {
// 緩存 Context,避免重複創建開銷
private static final Map<Class<?>, JAXBContext> CONTEXT_CACHE = new ConcurrentHashMap<>();
public static <T> String toXml(T obj, String encoding) {
try {
JAXBContext ctx = getContext(obj.getClass());
Marshaller m = ctx.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 換行縮進
m.setProperty(Marshaller.JAXB_ENCODING, encoding);
StringWriter sw = new StringWriter();
m.marshal(obj, sw);
return sw.toString();
} catch (JAXBException e) {
throw new RuntimeException("XML 序列化失敗", e);
}
}
public static <T> T fromXml(String xml, Class<T> clazz) {
try {
JAXBContext ctx = getContext(clazz);
Unmarshaller um = ctx.createUnmarshaller();
return clazz.cast(um.unmarshal(new StringReader(xml)));
} catch (JAXBException e) {
throw new RuntimeException("XML 反序列化失敗", e);
}
}
private static JAXBContext getContext(Class<?> clazz) {
return CONTEXT_CACHE.computeIfAbsent(clazz, c -> {
try { return JAXBContext.newInstance(c); }
catch (JAXBException e) { throw new RuntimeException(e); }
});
}
}
4. 測試驗證
@Test
public void roundTripTest() {
// 對象 → XML
Employee emp = new Employee();
emp.setId(1L);
emp.setName("Jane");
emp.setAge(10);
emp.setRole("Teacher");
emp.setGender("Male");
String xml = JaxbUtils.toXml(emp, "UTF-8");
System.out.println(xml);
// 輸出含換行縮進的完整 XML
// XML → 對象
Employee parsed = JaxbUtils.fromXml(xml, Employee.class);
assertEquals(emp.getName(), parsed.getName());
assertEquals(emp.getAge(), parsed.getAge());
}
進階技巧與避坑
- 命名空間處理:
@XmlSchema(namespace = "https://example.com", elementFormDefault = XmlNsForm.QUALIFIED) 於 package-info.java 定義。
- 集合包裝:
@XmlElementWrapper(name = "employees") @XmlElement(name = "employee") List<Employee> list; 生成雙層結構。
- 日期/時間類型:JAXB 不原生支援 Java 8
LocalDate,需編寫 XmlAdapter<String, LocalDate> 配合 @XmlJavaTypeAdapter。
- 大文件流式處理:JAXB 全量載入內存,超大 XML 請改用 StAX 或 SAX 流式解析。
- 線程安全:
Marshaller/Unmarshaller 非線程安全,每次轉換請 createMarshaller() 新建實例;JAXBContext 線程安全,務必緩存復用。
- 上一篇文章: Spring Boot 單元測試實戰:JUnit 4/5、MockMvc、參數化測試、REST API 測試與輸出捕獲全攻略
- 下一篇文章: Java 面向對象進階:Object 核心方法、類型轉換、動態綁定與多態機制深度解析
Copyright ©
程式碼之家 All Rights Reserved