杰瑞科技汇

Java XML序列化反序列化如何实现与优化?

在 Java 生态中,主要有以下几种方式来实现 XML 序列化/反序列化:

Java XML序列化反序列化如何实现与优化?-图1
(图片来源网络,侵删)
  1. JAXB (Java Architecture for XML Binding):这是目前最推荐、最标准的方式,从 Java 6 开始被内置到 JDK 中,它使用注解来简化整个过程。
  2. DOM / SAX / StAX 解析器:这些是底层的 XML API,DOM 将整个 XML 文档加载到内存中形成树状结构;SAX 是事件驱动的流式解析;StAX 是更现代的流式 API,它们非常灵活,但代码量较大,通常不直接用于简单的对象-XML 映射。
  3. 第三方库:如 XStream,它非常简单易用,但需要额外引入依赖。

下面,我们将重点讲解最主流的 JAXB 方式,并简要提及其他方法。


使用 JAXB (推荐)

JAXB 通过将 Java 字段/属性与 XML 元素/属性绑定,实现了对象和 XML 之间的自动转换,核心是 javax.xml.bind 包。

核心注解

  • @XmlRootElement: 将一个类映射为 XML 的根元素。
  • @XmlElement: 将一个字段/属性映射为 XML 的一个元素。
  • @XmlAttribute: 将一个字段/属性映射为 XML 元素的一个属性。
  • @XmlAccessorType: 控制哪些字段/属性会被映射,通常使用 XmlAccessType.FIELDXmlAccessType.PROPERTY
  • @XmlElementWrapper: 用于包装一个集合类型的元素,<books><book>...</book></books>

示例:完整的序列化与反序列化流程

假设我们有一个 User 类,需要将其转换为 XML。

准备 Java 类

创建一个 Java 类,并使用 JAXB 注解进行标记。

Java XML序列化反序列化如何实现与优化?-图2
(图片来源网络,侵删)
import javax.xml.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
// 1. 定义这个类是 XML 的根元素,name 指定 XML 标签名
@XmlRootElement(name = "user")
// 2. 指定哪些字段需要被序列化,FIELD 表示所有非 static、非 transient 的字段
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
    // 3. 将此字段映射为 XML 元素的属性
    @XmlAttribute
    private int id;
    // 4. 将此字段映射为 XML 元素
    @XmlElement
    private String name;
    @XmlElement
    private String email;
    // 5. 使用 @XmlElementWrapper 包装列表,并指定列表项的标签名
    @XmlElementWrapper(name = "phoneNumbers")
    @XmlElement(name = "phone")
    private List<String> phoneNumbers;
    // JAXB 需要一个无参构造函数
    public User() {
    }
    // 带参构造函数,方便创建对象
    public User(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.phoneNumbers = new ArrayList<>();
    }
    // Getters and Setters (JAXB 在序列化/反序列化时会使用它们)
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public List<String> getPhoneNumbers() { return phoneNumbers; }
    public void setPhoneNumbers(List<String> phoneNumbers) { this.phoneNumbers = phoneNumbers; }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", phoneNumbers=" + phoneNumbers +
                '}';
    }
}

序列化:将 Java 对象转换为 XML

创建一个工具类来执行序列化。

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
public class JaxbSerializer {
    public static String toXml(Object object) throws JAXBException {
        // 1. 创建 JAXBContext 实例,参数是需要序列化的类的 Class 对象
        JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
        // 2. 创建 Marshaller 实例,用于执行序列化操作
        Marshaller marshaller = jaxbContext.createMarshaller();
        // 3. 设置输出格式,例如美化输出(换行和缩进)
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        // 4. 使用 StringWriter 来捕获输出的 XML 字符串
        StringWriter writer = new StringWriter();
        // 5. 执行序列化,将对象写入到 writer 中
        marshaller.marshal(object, writer);
        // 6. 返回 XML 字符串
        return writer.toString();
    }
    public static void main(String[] args) {
        User user = new User(1, "张三", "zhangsan@example.com");
        user.getPhoneNumbers().add("13800138000");
        user.getPhoneNumbers().add("13900139000");
        try {
            String xml = toXml(user);
            System.out.println("序列化后的 XML:");
            System.out.println(xml);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

运行结果 (序列化后的 XML):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user id="1">
    <name>张三</name>
    <email>zhangsan@example.com</email>
    <phoneNumbers>
        <phone>13800138000</phone>
        <phone>13900139000</phone>
    </phoneNumbers>
</user>

反序列化:将 XML 转换为 Java 对象

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
public class JaxbDeserializer {
    public static <T> T fromXml(String xml, Class<T> clazz) throws JAXBException {
        // 1. 创建 JAXBContext 实例
        JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
        // 2. 创建 Unmarshaller 实例,用于执行反序列化操作
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        // 3. 使用 StringReader 来读取 XML 字符串
        StringReader reader = new StringReader(xml);
        // 4. 执行反序列化,将 XML 转换为 Java 对象
        // unmarshal() 的返回值是 XML 根元素对应的 Java 对象
        return (T) unmarshaller.unmarshal(reader);
    }
    public static void main(String[] args) {
        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
                "<user id=\"1\">\n" +
                "    <name>张三</name>\n" +
                "    <email>zhangsan@example.com</email>\n" +
                "    <phoneNumbers>\n" +
                "        <phone>13800138000</phone>\n" +
                "        <phone>13900139000</phone>\n" +
                "    </phoneNumbers>\n" +
                "</user>";
        try {
            User user = fromXml(xml, User.class);
            System.out.println("反序列化后的 User 对象:");
            System.out.println(user);
            System.out.println("Name: " + user.getName());
            System.out.println("Email: " + user.getEmail());
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

运行结果 (反序列化后的 User 对象):

反序列化后的 User 对象:
User{id=1, name='张三', email='zhangsan@example.com', phoneNumbers=[13800138000, 13900139000]}
Name: 张三
Email: zhangsan@example.com

使用第三方库 XStream

XStream 以其简洁的 API 而闻名,无需注解,直接使用反射即可完成映射。

Java XML序列化反序列化如何实现与优化?-图3
(图片来源网络,侵删)

添加依赖

如果你使用 Maven,在 pom.xml 中添加:

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.20</version> <!-- 使用最新版本 -->
</dependency>

序列化示例

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class XStreamSerializer {
    public static String toXml(Object object) {
        XStream xstream = new XStream(new DomDriver());
        // 可以设置别名,使 XML 更简洁
        xstream.alias("user", User.class);
        xstream.aliasField("id", User.class, "id"); // 将 User 的 id 字段映射为 XML 的 id 元素
        xstream.aliasField("name", User.class, "name");
        xstream.aliasField("email", User.class, "email");
        xstream.aliasField("phoneNumbers", User.class, "phoneNumbers");
        xstream.addImplicitCollection(User.class, "phoneNumbers", "phone", String.class); // 隐式集合
        return xstream.toXML(object);
    }
    public static void main(String[] args) {
        User user = new User(1, "李四", "lisi@example.com");
        user.getPhoneNumbers().add("13700137000");
        String xml = toXml(user);
        System.out.println("XStream 序列化后的 XML:");
        System.out.println(xml);
    }
}

反序列化示例

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class XStreamDeserializer {
    public static <T> T fromXml(String xml, Class<T> clazz) {
        XStream xstream = new XStream(new DomDriver());
        xstream.alias("user", User.class);
        // ... (和序列化时相同的别名设置)
        return (T) xstream.fromXML(xml);
    }
    public static void main(String[] args) {
        String xml = "<user>\n" +
                "  <id>1</id>\n" +
                "  <name>李四</name>\n" +
                "  <email>lisi@example.com</email>\n" +
                "  <phoneNumbers>\n" +
                "    <phone>13700137000</phone>\n" +
                "  </phoneNumbers>\n" +
                "</user>";
        User user = fromXml(xml, User.class);
        System.out.println("XStream 反序列化后的 User 对象:");
        System.out.println(user);
    }
}

使用标准 API (DOM/SAX)

这种方法非常底层,代码冗长,通常只在需要复杂的、非标准的 XML 操作时使用,不推荐用于简单的对象-XML 映射。

简单的 DOM 序列化示例 (不推荐用于对象映射)

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
public class DomSerializer {
    public static String toXml(User user) throws Exception {
        // 1. 创建 DocumentBuilderFactory 和 DocumentBuilder
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        // 2. 创建新的 Document 对象
        Document doc = docBuilder.newDocument();
        // 3. 创建根元素
        Element rootElement = doc.createElement("user");
        rootElement.setAttribute("id", String.valueOf(user.getId()));
        doc.appendChild(rootElement);
        // 4. 创建子元素
        Element nameElement = doc.createElement("name");
        nameElement.appendChild(doc.createTextNode(user.getName()));
        rootElement.appendChild(nameElement);
        Element emailElement = doc.createElement("email");
        emailElement.appendChild(doc.createTextNode(user.getEmail()));
        rootElement.appendChild(emailElement);
        // 5. 将 Document 对象转换为 XML 字符串
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");
        StringWriter writer = new StringWriter();
        transformer.transform(new DOMSource(doc), new StreamResult(writer));
        return writer.toString();
    }
    public static void main(String[] args) throws Exception {
        User user = new User(2, "王五", "wangwu@example.com");
        String xml = toXml(user);
        System.out.println("DOM 序列化后的 XML:");
        System.out.println(xml);
    }
}

总结与对比

特性 JAXB (推荐) XStream (第三方) DOM/SAX (标准 API)
易用性 ,注解驱动,代码简洁 非常高,几乎零配置,代码最简洁 ,需要手动构建和解析 XML 树
性能 良好 良好 对于大文件,SAX/StAX 性能更好
灵活性 良好,通过注解控制映射 极高,支持别名、转换器、过滤器等 极高,可以完全控制 XML 的生成和解析
依赖 JDK 内置 (Java 6+) 需要额外引入 xstream JDK 内置
适用场景 标准、对象到 XML 的映射,Web 服务等 快速原型开发,需要高度自定义 XML 格式 复杂的 XML 处理,如修改现有 XML、处理超大文件等

对于绝大多数 Java 应用程序,JAXB 是处理 XML 序列化和反序列化的最佳选择,它是标准、高效且易于使用的,只有在需要 JAXB 无法满足的特殊灵活性,或者希望最小化项目依赖时,才考虑 XStream,而 DOM/SAX 则应留给那些需要精细操作 XML 结构的底层任务。

分享:
扫描分享到社交APP
上一篇
下一篇