javax.xml.bind.JAXBContext操作XML的实现示例

 更新时间:2025年12月03日 10:07:11   作者:隔壁阿布都  
JAXB是Java标准API,用于Java对象与XML的相互转换,通过注解定义映射规则,本文就来详细的介绍一下javax.xml.bind.JAXBContext操作XML的实现,感兴趣的可以了解一下

JAXB(Java Architecture for XML Binding)是 Java 标准 API(JDK 1.6+ 内置,JDK 9+ 需手动引入依赖),用于实现 Java 对象与 XML 文档的相互转换(序列化/反序列化)。核心类 JAXBContext 负责管理 XML 与 Java 类型的绑定关系,配合 Marshaller(对象转 XML)和 Unmarshaller(XML 转对象)完成核心操作。

一、前置准备(依赖说明)

1. JDK 版本差异

  • JDK 8 及以下:JAXB 是 JDK 内置模块(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>
<!-- 运行时实现(必须,否则报错 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 元素的映射规则,常用注解如下:

注解作用场景说明
@XmlRootElement类级别标记该类为 XML 根元素(必须,否则无法序列化),可指定 name(XML 根节点名)
@XmlElement字段/ getter 方法映射 Java 字段到 XML 子元素,可指定 name(XML 子节点名)、required(是否必选)
@XmlAttribute字段/ getter 方法映射 Java 字段到 XML 元素的属性(而非子元素)
@XmlTransient字段/ getter 方法忽略该字段(不参与 XML 序列化/反序列化)
@XmlAccessorType类级别指定字段访问策略(如 FIELD:直接访问字段,无需 getter/setter)
@XmlList集合字段将集合元素序列化为 XML 单个元素的多个值(用空格分隔)
@XmlRootElement类级别根元素注解,必须存在

三、完整使用步骤(示例驱动)

场景:实现User类与 XML 的相互转换,包含嵌套对象、集合、属性

步骤 1:定义 Java 实体类(带 JAXB 注解)

import javax.xml.bind.annotation.*;
import java.util.List;

// 根元素:XML 根节点名为 <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;

        // 必须有默认无参构造器(JAXB 反射创建对象时需要)
        public Address() {}
        public Address(String province, String city) {
            this.province = province;
            this.city = city;
        }

        // getter/setter(可选,因使用 FIELD 访问策略)
        // ...
    }

    // 必须有默认无参构造器(JAXB 强制要求)
    public User() {}

    // 带参构造器(方便创建对象)
    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(可选,若需外部操作字段)
    // ...
}

关键注意:

  1. 所有参与序列化的类(包括嵌套类)必须有 默认无参构造器(JAXB 反射实例化需要)。
  2. 注解可加在字段或 getter 方法上,建议统一风格(如示例用 XmlAccessType.FIELD 直接操作字段)。

步骤 2:Java 对象 → XML(序列化,Marshaller)

核心流程:

  1. 通过 JAXBContext.newInstance(Class...) 创建上下文(指定要绑定的 Java 类)。
  2. 从上下文获取 Marshaller 实例。
  3. 配置 Marshaller(如格式化输出、编码、忽略XML声明等)。
  4. 调用 marshall() 方法序列化(输出到文件、流、字符串等)。

示例代码:对象转 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. 创建 Java 对象(模拟数据)
        User.Address address = new User.Address("广东省", "深圳市");
        User user = new User(
            1001L,
            "张三",
            25,
            address,
            Arrays.asList("篮球", "足球", "编程")
        );

        try {
            // 2. 创建 JAXBContext(参数为要绑定的实体类)
            JAXBContext context = JAXBContext.newInstance(User.class);

            // 3. 获取 Marshaller 实例(负责序列化)
            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. 序列化到字符串(便于网络传输等场景)
            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)

核心流程:

  1. 同样通过 JAXBContext.newInstance(Class...) 创建上下文。
  2. 从上下文获取 Unmarshaller 实例。
  3. 调用 unmarshal() 方法反序列化(从文件、流、字符串读取 XML)。

示例代码:XML 文件/字符串转对象

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. 创建 JAXBContext
            JAXBContext context = JAXBContext.newInstance(User.class);

            // 2. 获取 Unmarshaller 实例(负责反序列化)
            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();
        }
    }
}

输出结果

从文件解析的 User:
用户ID:1001
姓名:张三
地址:广东省-深圳市
爱好:[篮球, 足球, 编程]

从字符串解析的 User:
用户ID:1002
姓名:李四
地址:浙江省-杭州市
爱好:[读书, 旅行]

四、复杂场景扩展

1. 集合根节点(多个对象的 XML 序列化)

若需序列化多个 User 对象(如 List<User>),直接序列化集合会报错(无根元素),需创建一个“包装类”:

@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
public class UserList {
    @XmlElement(name = "user") // 每个 User 对应 <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:实现日期适配器

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) // 应用适配器
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(...) 未传入所有参与序列化的类(如嵌套类、集合元素类)。
  • 解决:确保所有相关类都被包含,如 JAXBContext.newInstance(User.class, Address.class)

2. 报错No default constructor found

  • 原因:实体类(或嵌套类)没有默认无参构造器。
  • 解决:为所有实体类添加无参构造器(即使是空实现)。

3. 中文乱码

  • 原因:Marshaller 编码未设置为 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 参数,开放模块访问:
    --add-opens java.base/java.lang=ALL-UNNAMED
    --add-opens java.base/java.util=ALL-UNNAMED
    

六、核心 API 总结

类/接口作用核心方法
JAXBContext管理绑定关系(线程安全,可复用)newInstance(Class...):创建上下文
MarshallerJava 对象 → XMLmarshal(Object, OutputStream/File/StringWriter)
UnmarshallerXML → Java 对象unmarshal(InputStream/File/StringReader)

通过以上步骤,你可以完整实现 XML 与 Java 对象的相互转换,覆盖基本场景和常见复杂需求。JAXB 无需手动解析 XML 标签,通过注解自动映射,大幅简化 XML 处理代码。

到此这篇关于javax.xml.bind.JAXBContext操作XML的实现示例的文章就介绍到这了,更多相关javax.xml.bind.JAXBContext操作XML内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在SpringBoot项目中实现图片缩略图功能的三种方案

    在SpringBoot项目中实现图片缩略图功能的三种方案

    本文介绍了在SpringBoot项目中实现图片缩略图的三种方案:使用Thumbnailator库、JavaAWT原生库以及集成MinIO自动生成缩略图,每种方案都详细介绍了实现步骤,并提供了完整的案例,需要的朋友可以参考下
    2025-10-10
  • springboot实现string转json json里面带数组

    springboot实现string转json json里面带数组

    这篇文章主要介绍了springboot实现string转json json里面带数组,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • 10个Java程序员熟悉的面向对象设计原则

    10个Java程序员熟悉的面向对象设计原则

    这篇文章主要为大家详细介绍了Java程序员应当知道的10个面向对象设计原则,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • 实例讲解spring boot 多线程

    实例讲解spring boot 多线程

    这篇文章主要介绍了spring boot 多线程的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • Spring Security6 最新版配置及实现动态权限管理

    Spring Security6 最新版配置及实现动态权限管理

    Spring Security 在最近几个版本中配置的写法都有一些变化,很多常见的方法都废弃了,并且将在未来的 Spring Security7 中移除,因此又补充了一些新的内容,重新发一下,供各位使用 Spring Security 的小伙伴们参考,需要的朋友可以参考下
    2024-03-03
  • Kafka单节点伪分布式集群搭建实现过程详解

    Kafka单节点伪分布式集群搭建实现过程详解

    这篇文章主要介绍了Kafka单节点伪分布式集群搭建实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • Java虚拟机JVM性能优化(二):编译器

    Java虚拟机JVM性能优化(二):编译器

    这篇文章主要介绍了Java虚拟机JVM性能优化(二):编译器,本文先是讲解了不同种类的编译器,并对客户端编译,服务器端编译器和多层编译的运行性能进行了对比,然后给出了几种常见的JVM优化方法,需要的朋友可以参考下
    2014-09-09
  • 解析Java的Jackson库中对象的序列化与数据泛型绑定

    解析Java的Jackson库中对象的序列化与数据泛型绑定

    这篇文章主要介绍了解析Java的Jackson库中对象的序列化与数据泛型绑定,Jackson通常被用来实现Java对象和JSON数据的相互转换功能,需要的朋友可以参考下
    2016-01-01
  • SpringMVC响应处理详细解读

    SpringMVC响应处理详细解读

    Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet,Spring MVC 角色划分清晰,分工明细,本章来讲解SpringMVC数据响应
    2022-07-07
  • redis setIfAbsent和setnx的区别与使用说明

    redis setIfAbsent和setnx的区别与使用说明

    这篇文章主要介绍了redis setIfAbsent和setnx的区别与使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08

最新评论