javax.xml.bind.JAXBContext操作XML的實(shí)現(xiàn)示例
JAXB(Java Architecture for XML Binding)是 Java 標(biāo)準(zhǔn) API(JDK 1.6+ 內(nèi)置,JDK 9+ 需手動(dòng)引入依賴),用于實(shí)現(xiàn) Java 對(duì)象與 XML 文檔的相互轉(zhuǎn)換(序列化/反序列化)。核心類 JAXBContext 負(fù)責(zé)管理 XML 與 Java 類型的綁定關(guān)系,配合 Marshaller(對(duì)象轉(zhuǎn) XML)和 Unmarshaller(XML 轉(zhuǎn)對(duì)象)完成核心操作。
一、前置準(zhǔn)備(依賴說明)
1. JDK 版本差異
- JDK 8 及以下:JAXB 是 JDK 內(nèi)置模塊(
javax.xml.bind),無需額外依賴。 - JDK 9 及以上:JAXB 被移除出默認(rèn)模塊(模塊化改革),需手動(dòng)引入 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>
<!-- 運(yùn)行時(shí)實(shí)現(xiàn)(必須,否則報(bào)錯(cuò) 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 實(shí)體 → XML 映射)
JAXB 通過注解定義 Java 類與 XML 元素的映射規(guī)則,常用注解如下:
| 注解 | 作用場景 | 說明 |
|---|---|---|
| @XmlRootElement | 類級(jí)別 | 標(biāo)記該類為 XML 根元素(必須,否則無法序列化),可指定 name(XML 根節(jié)點(diǎn)名) |
| @XmlElement | 字段/ getter 方法 | 映射 Java 字段到 XML 子元素,可指定 name(XML 子節(jié)點(diǎn)名)、required(是否必選) |
| @XmlAttribute | 字段/ getter 方法 | 映射 Java 字段到 XML 元素的屬性(而非子元素) |
| @XmlTransient | 字段/ getter 方法 | 忽略該字段(不參與 XML 序列化/反序列化) |
| @XmlAccessorType | 類級(jí)別 | 指定字段訪問策略(如 FIELD:直接訪問字段,無需 getter/setter) |
| @XmlList | 集合字段 | 將集合元素序列化為 XML 單個(gè)元素的多個(gè)值(用空格分隔) |
| @XmlRootElement | 類級(jí)別 | 根元素注解,必須存在 |
三、完整使用步驟(示例驅(qū)動(dòng))
場景:實(shí)現(xiàn)User類與 XML 的相互轉(zhuǎn)換,包含嵌套對(duì)象、集合、屬性
步驟 1:定義 Java 實(shí)體類(帶 JAXB 注解)
import javax.xml.bind.annotation.*;
import java.util.List;
// 根元素:XML 根節(jié)點(diǎn)名為 <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;
// 嵌套對(duì)象(XML 子元素嵌套)
@XmlElement(name = "address")
private Address address;
// 集合字段(XML 子元素:<hobbies>籃球 足球</hobbies>)
@XmlElement(name = "hobbies")
@XmlList // 集合元素序列化為單個(gè)元素的多個(gè)值
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;
// 必須有默認(rèn)無參構(gòu)造器(JAXB 反射創(chuàng)建對(duì)象時(shí)需要)
public Address() {}
public Address(String province, String city) {
this.province = province;
this.city = city;
}
// getter/setter(可選,因使用 FIELD 訪問策略)
// ...
}
// 必須有默認(rèn)無參構(gòu)造器(JAXB 強(qiáng)制要求)
public User() {}
// 帶參構(gòu)造器(方便創(chuàng)建對(duì)象)
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)鍵注意:
- 所有參與序列化的類(包括嵌套類)必須有 默認(rèn)無參構(gòu)造器(JAXB 反射實(shí)例化需要)。
- 注解可加在字段或 getter 方法上,建議統(tǒng)一風(fēng)格(如示例用
XmlAccessType.FIELD直接操作字段)。
步驟 2:Java 對(duì)象 → XML(序列化,Marshaller)
核心流程:
- 通過 JAXBContext.newInstance(Class...) 創(chuàng)建上下文(指定要綁定的 Java 類)。
- 從上下文獲取 Marshaller 實(shí)例。
- 配置 Marshaller(如格式化輸出、編碼、忽略XML聲明等)。
- 調(diào)用 marshall() 方法序列化(輸出到文件、流、字符串等)。
示例代碼:對(duì)象轉(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 對(duì)象(模擬數(shù)據(jù))
User.Address address = new User.Address("廣東省", "深圳市");
User user = new User(
1001L,
"張三",
25,
address,
Arrays.asList("籃球", "足球", "編程")
);
try {
// 2. 創(chuàng)建 JAXBContext(參數(shù)為要綁定的實(shí)體類)
JAXBContext context = JAXBContext.newInstance(User.class);
// 3. 獲取 Marshaller 實(shí)例(負(fù)責(zé)序列化)
Marshaller marshaller = context.createMarshaller();
// 4. 配置 Marshaller
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 格式化輸出(換行、縮進(jìn))
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 對(duì)象(反序列化,Unmarshaller)
核心流程:
- 同樣通過
JAXBContext.newInstance(Class...)創(chuàng)建上下文。 - 從上下文獲取
Unmarshaller實(shí)例。 - 調(diào)用
unmarshal()方法反序列化(從文件、流、字符串讀取 XML)。
示例代碼:XML 文件/字符串轉(zhuǎn)對(duì)象
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 實(shí)例(負(fù)責(zé)反序列化)
Unmarshaller unmarshaller = context.createUnmarshaller();
// 3. 從 XML 文件反序列化到對(duì)象
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 字符串反序列化到對(duì)象
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ù)雜場景擴(kuò)展
1. 集合根節(jié)點(diǎn)(多個(gè)對(duì)象的 XML 序列化)
若需序列化多個(gè) User 對(duì)象(如 List<User>),直接序列化集合會(huì)報(bào)錯(cuò)(無根元素),需創(chuàng)建一個(gè)“包裝類”:
@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
public class UserList {
@XmlElement(name = "user") // 每個(gè) User 對(duì)應(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. 日期格式自定義
默認(rèn)日期字段(Date/LocalDate)序列化格式不友好,可通過 @XmlJavaTypeAdapter 自定義適配器:
步驟 1:實(shí)現(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:在實(shí)體類字段上使用
@XmlElement(name = "createTime") @XmlJavaTypeAdapter(DateAdapter.class) // 應(yīng)用適配器 private Date createTime;
序列化后 XML 效果:
<createTime>2025-11-25 14:30:00</createTime>
3. 忽略空值字段
默認(rèn)情況下,空值字段(如 age = null)會(huì)生成空的 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;
五、常見問題與注意事項(xiàng)
1. 報(bào)錯(cuò)JAXBException: Class ... nor any of its super class is known to this context
- 原因:
JAXBContext.newInstance(...)未傳入所有參與序列化的類(如嵌套類、集合元素類)。 - 解決:確保所有相關(guān)類都被包含,如
JAXBContext.newInstance(User.class, Address.class)。
2. 報(bào)錯(cuò)No default constructor found
- 原因:實(shí)體類(或嵌套類)沒有默認(rèn)無參構(gòu)造器。
- 解決:為所有實(shí)體類添加無參構(gòu)造器(即使是空實(shí)現(xiàn))。
3. 中文亂碼
- 原因:
Marshaller編碼未設(shè)置為 UTF-8,或文件讀取時(shí)編碼不匹配。 - 解決:
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); // 序列化時(shí) // 反序列化文件時(shí)指定編碼 FileInputStream fis = new FileInputStream(xmlFile); User user = (User) unmarshaller.unmarshal(new InputStreamReader(fis, "UTF-8"));
4. JDK 9+ 模塊訪問限制
- 報(bào)錯(cuò):
Module java.base does not "opens java.lang" to unnamed module @xxx。 - 解決:運(yùn)行時(shí)添加 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 對(duì)象 → XML | marshal(Object, OutputStream/File/StringWriter) |
| Unmarshaller | XML → Java 對(duì)象 | unmarshal(InputStream/File/StringReader) |
通過以上步驟,你可以完整實(shí)現(xiàn) XML 與 Java 對(duì)象的相互轉(zhuǎn)換,覆蓋基本場景和常見復(fù)雜需求。JAXB 無需手動(dòng)解析 XML 標(biāo)簽,通過注解自動(dòng)映射,大幅簡化 XML 處理代碼。
到此這篇關(guān)于javax.xml.bind.JAXBContext操作XML的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)javax.xml.bind.JAXBContext操作XML內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringMVC集成Web與MVC執(zhí)行流程和數(shù)據(jù)響應(yīng)及交互相關(guān)介紹全面總結(jié)
Spring MVC 是 Spring 提供的一個(gè)基于 MVC 設(shè)計(jì)模式的輕量級(jí) Web 開發(fā)框架,本質(zhì)上相當(dāng)于 Servlet,Spring MVC 角色劃分清晰,分工明細(xì),這篇文章主要介紹了SpringMVC集成Web與MVC執(zhí)行流程和數(shù)據(jù)響應(yīng)及交互2022-10-10
Springmvc如何實(shí)現(xiàn)向前臺(tái)傳遞數(shù)據(jù)
這篇文章主要介紹了Springmvc如何實(shí)現(xiàn)向前臺(tái)傳遞數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
clickhouse?批量插入數(shù)據(jù)及ClickHouse常用命令詳解
這篇文章主要介紹了clickhouse?批量插入數(shù)據(jù)及ClickHouse常用命令,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
java使用Socket實(shí)現(xiàn)SMTP協(xié)議發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了java使用Socket實(shí)現(xiàn)SMTP協(xié)議發(fā)送郵件的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-05-05
詳解Java動(dòng)態(tài)加載數(shù)據(jù)庫驅(qū)動(dòng)
本篇文章主要介紹了詳解Java動(dòng)態(tài)加載數(shù)據(jù)庫驅(qū)動(dòng),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
高并發(fā)環(huán)境下安全修改同一行數(shù)據(jù)庫數(shù)據(jù)的策略分享
隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展,越來越多的應(yīng)用需要在高并發(fā)環(huán)境中運(yùn)行,數(shù)據(jù)庫的并發(fā)控制成為了業(yè)務(wù)的關(guān)鍵,本文將介紹如何在高并發(fā)情況下,安全地修改數(shù)據(jù)庫中的同一行數(shù)據(jù),需要的可以參考一下2023-06-06
SpringSecurity授權(quán)實(shí)現(xiàn)基本思路
本文介紹了SpringSecurity中使用FilterSecurityInterceptor進(jìn)行權(quán)限校驗(yàn)的基本方法,通過SecurityContextHolder獲取Authentication中的權(quán)限信息,感興趣的朋友跟隨小編一起看看吧2024-10-10

