javax.xml.bind.JAXBContext操作XML的實現(xiàn)示例
JAXB(Java Architecture for XML Binding)是 Java 標準 API(JDK 1.6+ 內(nèi)置,JDK 9+ 需手動引入依賴),用于實現(xiàn) Java 對象與 XML 文檔的相互轉(zhuǎn)換(序列化/反序列化)。核心類 JAXBContext 負責(zé)管理 XML 與 Java 類型的綁定關(guān)系,配合 Marshaller(對象轉(zhuǎn) XML)和 Unmarshaller(XML 轉(zhuǎn)對象)完成核心操作。
一、前置準備(依賴說明)
1. JDK 版本差異
- JDK 8 及以下:JAXB 是 JDK 內(nèi)置模塊(
javax.xml.bind),無需額外依賴。 - JDK 9 及以上:JAXB 被移除出默認模塊(模塊化改革),需手動引入 Maven/Gradle 依賴(遷移到 Jakarta EE 后包名不變,但需指定依賴):
Maven 依賴(JDK 9+)
<!-- JAXB 核心依賴 -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
<!-- 運行時實現(xiàn)(必須,否則報錯 ClassNotFoundException) -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.3</version>
<scope>runtime</scope>
</dependency>
<!-- 用于 JDK 9+ 模塊支持(可選,解決模塊訪問限制) -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.3</version>
</dependency>
Gradle 依賴(JDK 9+)
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.3' runtimeOnly 'com.sun.xml.bind:jaxb-impl:2.3.3' runtimeOnly 'com.sun.xml.bind:jaxb-core:2.3.3'
二、核心注解說明(Java 實體 → XML 映射)
JAXB 通過注解定義 Java 類與 XML 元素的映射規(guī)則,常用注解如下:
| 注解 | 作用場景 | 說明 |
|---|---|---|
| @XmlRootElement | 類級別 | 標記該類為 XML 根元素(必須,否則無法序列化),可指定 name(XML 根節(jié)點名) |
| @XmlElement | 字段/ getter 方法 | 映射 Java 字段到 XML 子元素,可指定 name(XML 子節(jié)點名)、required(是否必選) |
| @XmlAttribute | 字段/ getter 方法 | 映射 Java 字段到 XML 元素的屬性(而非子元素) |
| @XmlTransient | 字段/ getter 方法 | 忽略該字段(不參與 XML 序列化/反序列化) |
| @XmlAccessorType | 類級別 | 指定字段訪問策略(如 FIELD:直接訪問字段,無需 getter/setter) |
| @XmlList | 集合字段 | 將集合元素序列化為 XML 單個元素的多個值(用空格分隔) |
| @XmlRootElement | 類級別 | 根元素注解,必須存在 |
三、完整使用步驟(示例驅(qū)動)
場景:實現(xiàn)User類與 XML 的相互轉(zhuǎn)換,包含嵌套對象、集合、屬性
步驟 1:定義 Java 實體類(帶 JAXB 注解)
import javax.xml.bind.annotation.*;
import java.util.List;
// 根元素:XML 根節(jié)點名為 <user>
@XmlRootElement(name = "user")
// 訪問策略:直接操作字段(無需 getter/setter,簡化代碼)
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
// XML 元素的屬性:<user id="1001">
@XmlAttribute(name = "id")
private Long userId;
// XML 子元素:<username>張三</username>(必選)
@XmlElement(name = "username", required = true)
private String name;
// XML 子元素:<age>25</age>
@XmlElement
private Integer age;
// 嵌套對象(XML 子元素嵌套)
@XmlElement(name = "address")
private Address address;
// 集合字段(XML 子元素:<hobbies>籃球 足球</hobbies>)
@XmlElement(name = "hobbies")
@XmlList // 集合元素序列化為單個元素的多個值
private List<String> hobbies;
// 忽略該字段(不生成 XML 元素)
@XmlTransient
private String password;
// 嵌套類(地址信息)
@XmlAccessorType(XmlAccessType.FIELD)
public static class Address {
@XmlElement(name = "province")
private String province;
@XmlElement(name = "city")
private String city;
// 必須有默認無參構(gòu)造器(JAXB 反射創(chuàng)建對象時需要)
public Address() {}
public Address(String province, String city) {
this.province = province;
this.city = city;
}
// getter/setter(可選,因使用 FIELD 訪問策略)
// ...
}
// 必須有默認無參構(gòu)造器(JAXB 強制要求)
public User() {}
// 帶參構(gòu)造器(方便創(chuàng)建對象)
public User(Long userId, String name, Integer age, Address address, List<String> hobbies) {
this.userId = userId;
this.name = name;
this.age = age;
this.address = address;
this.hobbies = hobbies;
}
// getter/setter(可選,若需外部操作字段)
// ...
}
關(guān)鍵注意:
- 所有參與序列化的類(包括嵌套類)必須有 默認無參構(gòu)造器(JAXB 反射實例化需要)。
- 注解可加在字段或 getter 方法上,建議統(tǒng)一風(fēng)格(如示例用
XmlAccessType.FIELD直接操作字段)。
步驟 2:Java 對象 → XML(序列化,Marshaller)
核心流程:
- 通過 JAXBContext.newInstance(Class...) 創(chuàng)建上下文(指定要綁定的 Java 類)。
- 從上下文獲取 Marshaller 實例。
- 配置 Marshaller(如格式化輸出、編碼、忽略XML聲明等)。
- 調(diào)用 marshall() 方法序列化(輸出到文件、流、字符串等)。
示例代碼:對象轉(zhuǎn) XML 文件/字符串
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
import java.io.StringWriter;
import java.util.Arrays;
public class JaxbMarshallerDemo {
public static void main(String[] args) {
// 1. 創(chuàng)建 Java 對象(模擬數(shù)據(jù))
User.Address address = new User.Address("廣東省", "深圳市");
User user = new User(
1001L,
"張三",
25,
address,
Arrays.asList("籃球", "足球", "編程")
);
try {
// 2. 創(chuàng)建 JAXBContext(參數(shù)為要綁定的實體類)
JAXBContext context = JAXBContext.newInstance(User.class);
// 3. 獲取 Marshaller 實例(負責(zé)序列化)
Marshaller marshaller = context.createMarshaller();
// 4. 配置 Marshaller
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 格式化輸出(換行、縮進)
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); // 編碼格式
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false); // 是否省略 XML 聲明(<?xml ...?>)
// 5. 序列化到 XML 文件
File xmlFile = new File("user.xml");
marshaller.marshal(user, xmlFile);
System.out.println("XML 文件已生成:" + xmlFile.getAbsolutePath());
// 6. 序列化到字符串(便于網(wǎng)絡(luò)傳輸?shù)葓鼍埃?
StringWriter writer = new StringWriter();
marshaller.marshal(user, writer);
String xmlStr = writer.toString();
System.out.println("\nXML 字符串:");
System.out.println(xmlStr);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
生成的 XML 文件(user.xml)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user id="1001">
<username>張三</username>
<age>25</age>
<address>
<province>廣東省</province>
<city>深圳市</city>
</address>
<hobbies>籃球 足球 編程</hobbies>
</user>
步驟 3:XML → Java 對象(反序列化,Unmarshaller)
核心流程:
- 同樣通過
JAXBContext.newInstance(Class...)創(chuàng)建上下文。 - 從上下文獲取
Unmarshaller實例。 - 調(diào)用
unmarshal()方法反序列化(從文件、流、字符串讀取 XML)。
示例代碼:XML 文件/字符串轉(zhuǎn)對象
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.io.StringReader;
public class JaxbUnmarshallerDemo {
public static void main(String[] args) {
try {
// 1. 創(chuàng)建 JAXBContext
JAXBContext context = JAXBContext.newInstance(User.class);
// 2. 獲取 Unmarshaller 實例(負責(zé)反序列化)
Unmarshaller unmarshaller = context.createUnmarshaller();
// 3. 從 XML 文件反序列化到對象
File xmlFile = new File("user.xml");
User userFromFile = (User) unmarshaller.unmarshal(xmlFile);
System.out.println("從文件解析的 User:");
System.out.println("用戶ID:" + userFromFile.getUserId());
System.out.println("姓名:" + userFromFile.getName());
System.out.println("地址:" + userFromFile.getAddress().getProvince() + "-" + userFromFile.getAddress().getCity());
System.out.println("愛好:" + userFromFile.getHobbies());
// 4. 從 XML 字符串反序列化到對象
String xmlStr = """
<?xml version="1.0" encoding="UTF-8"?>
<user id="1002">
<username>李四</username>
<age>30</age>
<address>
<province>浙江省</province>
<city>杭州市</city>
</address>
<hobbies>讀書 旅行</hobbies>
</user>
""";
StringReader reader = new StringReader(xmlStr);
User userFromStr = (User) unmarshaller.unmarshal(reader);
System.out.println("\n從字符串解析的 User:");
System.out.println("用戶ID:" + userFromStr.getUserId());
System.out.println("姓名:" + userFromStr.getName());
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
輸出結(jié)果
從文件解析的 User:
用戶ID:1001
姓名:張三
地址:廣東省-深圳市
愛好:[籃球, 足球, 編程]從字符串解析的 User:
用戶ID:1002
姓名:李四
地址:浙江省-杭州市
愛好:[讀書, 旅行]
四、復(fù)雜場景擴展
1. 集合根節(jié)點(多個對象的 XML 序列化)
若需序列化多個 User 對象(如 List<User>),直接序列化集合會報錯(無根元素),需創(chuàng)建一個“包裝類”:
@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
public class UserList {
@XmlElement(name = "user") // 每個 User 對應(yīng) <user> 子元素
private List<User> userList;
public UserList() {}
public UserList(List<User> userList) {
this.userList = userList;
}
// getter/setter
}
序列化示例:
List<User> users = Arrays.asList(user1, user2);
UserList userList = new UserList(users);
marshaller.marshal(userList, new File("users.xml"));
生成的 XML:
<users>
<user id="1001">...</user>
<user id="1002">...</user>
</users>
2. 日期格式自定義
默認日期字段(Date/LocalDate)序列化格式不友好,可通過 @XmlJavaTypeAdapter 自定義適配器:
步驟 1:實現(xiàn)日期適配器
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;
// 適配 Date <-> String(自定義格式)
public class DateAdapter extends XmlAdapter<String, Date> {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public Date unmarshal(String xmlStr) throws Exception {
return sdf.parse(xmlStr);
}
@Override
public String marshal(Date date) throws Exception {
return sdf.format(date);
}
}
步驟 2:在實體類字段上使用
@XmlElement(name = "createTime") @XmlJavaTypeAdapter(DateAdapter.class) // 應(yīng)用適配器 private Date createTime;
序列化后 XML 效果:
<createTime>2025-11-25 14:30:00</createTime>
3. 忽略空值字段
默認情況下,空值字段(如 age = null)會生成空的 XML 元素(<age/>),可通過配置 Marshaller 忽略空值:
// JAXB 2.2+ 支持,需引入 jaxb-impl 依賴
marshaller.setProperty("com.sun.xml.bind.marshaller.NullPolicy", NullPolicy.SKIP);
或通過注解 @XmlElement(nillable = false) 配合配置:
@XmlElement(nillable = false) private Integer age;
五、常見問題與注意事項
1. 報錯JAXBException: Class ... nor any of its super class is known to this context
- 原因:
JAXBContext.newInstance(...)未傳入所有參與序列化的類(如嵌套類、集合元素類)。 - 解決:確保所有相關(guān)類都被包含,如
JAXBContext.newInstance(User.class, Address.class)。
2. 報錯No default constructor found
- 原因:實體類(或嵌套類)沒有默認無參構(gòu)造器。
- 解決:為所有實體類添加無參構(gòu)造器(即使是空實現(xiàn))。
3. 中文亂碼
- 原因:
Marshaller編碼未設(shè)置為 UTF-8,或文件讀取時編碼不匹配。 - 解決:
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); // 序列化時 // 反序列化文件時指定編碼 FileInputStream fis = new FileInputStream(xmlFile); User user = (User) unmarshaller.unmarshal(new InputStreamReader(fis, "UTF-8"));
4. JDK 9+ 模塊訪問限制
- 報錯:
Module java.base does not "opens java.lang" to unnamed module @xxx。 - 解決:運行時添加 JVM 參數(shù),開放模塊訪問:
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED
六、核心 API 總結(jié)
| 類/接口 | 作用 | 核心方法 |
|---|---|---|
| JAXBContext | 管理綁定關(guān)系(線程安全,可復(fù)用) | newInstance(Class...):創(chuàng)建上下文 |
| Marshaller | Java 對象 → XML | marshal(Object, OutputStream/File/StringWriter) |
| Unmarshaller | XML → Java 對象 | unmarshal(InputStream/File/StringReader) |
通過以上步驟,你可以完整實現(xiàn) XML 與 Java 對象的相互轉(zhuǎn)換,覆蓋基本場景和常見復(fù)雜需求。JAXB 無需手動解析 XML 標簽,通過注解自動映射,大幅簡化 XML 處理代碼。
到此這篇關(guān)于javax.xml.bind.JAXBContext操作XML的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)javax.xml.bind.JAXBContext操作XML內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在SpringBoot項目中實現(xiàn)圖片縮略圖功能的三種方案
本文介紹了在SpringBoot項目中實現(xiàn)圖片縮略圖的三種方案:使用Thumbnailator庫、JavaAWT原生庫以及集成MinIO自動生成縮略圖,每種方案都詳細介紹了實現(xiàn)步驟,并提供了完整的案例,需要的朋友可以參考下2025-10-10
springboot實現(xiàn)string轉(zhuǎn)json json里面帶數(shù)組
這篇文章主要介紹了springboot實現(xiàn)string轉(zhuǎn)json json里面帶數(shù)組,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
10個Java程序員熟悉的面向?qū)ο笤O(shè)計原則
這篇文章主要為大家詳細介紹了Java程序員應(yīng)當(dāng)知道的10個面向?qū)ο笤O(shè)計原則,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
Spring Security6 最新版配置及實現(xiàn)動態(tài)權(quán)限管理
Spring Security 在最近幾個版本中配置的寫法都有一些變化,很多常見的方法都廢棄了,并且將在未來的 Spring Security7 中移除,因此又補充了一些新的內(nèi)容,重新發(fā)一下,供各位使用 Spring Security 的小伙伴們參考,需要的朋友可以參考下2024-03-03
Kafka單節(jié)點偽分布式集群搭建實現(xiàn)過程詳解
這篇文章主要介紹了Kafka單節(jié)點偽分布式集群搭建實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11
解析Java的Jackson庫中對象的序列化與數(shù)據(jù)泛型綁定
這篇文章主要介紹了解析Java的Jackson庫中對象的序列化與數(shù)據(jù)泛型綁定,Jackson通常被用來實現(xiàn)Java對象和JSON數(shù)據(jù)的相互轉(zhuǎn)換功能,需要的朋友可以參考下2016-01-01
redis setIfAbsent和setnx的區(qū)別與使用說明
這篇文章主要介紹了redis setIfAbsent和setnx的區(qū)別與使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

