Skip to content

使用 Object-XML 映射器编组 XML (Marshalling XML by Using Object-XML Mappers)

本章介绍 Spring 的对象-XML 映射(Object-XML Mapping,简称 O-X mapping)支持。O-X 映射是指将 XML 文档与对象相互转换的过程。这一转换过程也被称为 XML 编组(Marshalling)或 XML 序列化(Serialization)。

在 O-X 映射领域:

  • Marshaller(编组器):负责将对象(图)序列化为 XML。
  • Unmarshaller(解组器):负责将 XML 反序列化为对象图。

Spring OXM 的优势

使用 Spring 进行 O-X 映射的一些好处包括:

  • 易于配置:Spring 的 Bean 工厂使得配置编组器变得非常容易,无需手动创建 JAXB 上下文、JiBX 绑定工厂等。你可以像配置应用中的其他任何 Bean 一样配置编组器。此外,许多编组器还提供基于 XML 命名空间的配置,使配置更加简单。
  • 一致的接口:Spring 的 O-X 映射通过两个全局接口运行:MarshallerUnmarshaller。这些抽象让你能以相对较低的成本切换 O-X 映射框架,而无需修改执行编组的类。这种方法还有一个额外的好处,即可以非侵入式地混合使用不同的编组技术(例如,一部分编组使用 JAXB,另一部分使用 XStream)。
  • 一致的异常体系:Spring 将底层 O-X 映射工具的异常转换为其自身的异常体系,以 XmlMappingException 为根异常。这些运行时异常包装了原始异常,因此不会丢失任何信息。

MarshallerUnmarshaller

理解 Marshaller

Spring 将所有编组操作抽象在 org.springframework.oxm.Marshaller 接口之后。

java
public interface Marshaller {
    /**
     * 将给定的对象图编组到提供的 Result 中。
     */
    void marshal(Object graph, Result result) throws XmlMappingException, IOException;
}

Result 是一个标记接口,代表 XML 输出的抽象。常见的实现包括:

Result 实现包装的 XML 表示
DOMResultorg.w3c.dom.Node
SAXResultorg.xml.sax.ContentHandler
StreamResultjava.io.File, java.io.OutputStream, 或 java.io.Writer

理解 Unmarshaller

与之对应的是 org.springframework.oxm.Unmarshaller 接口。

java
public interface Unmarshaller {
    /**
     * 将提供的 Source 解组为一个对象图。
     */
    Object unmarshal(Source source) throws XmlMappingException, IOException;
}

Source 也是一个抽象接口,其实现包括:

Source 实现包装的 XML 表示
DOMSourceorg.w3c.dom.Node
SAXSourceorg.xml.sax.InputSourceorg.xml.sax.XMLReader
StreamSourcejava.io.File, java.io.InputStream, 或 java.io.Reader

使用示例

以下示例演示了如何编组和解组一个简单的 Settings JavaBean。

java
public class Application {
    private static final String FILE_NAME = "settings.xml";
    private Settings settings = new Settings();
    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public void setUnmarshaller(Unmarshaller unmarshaller) {
        this.unmarshaller = unmarshaller;
    }

    public void saveSettings() throws IOException {
        try (FileOutputStream os = new FileOutputStream(FILE_NAME)) {
            this.marshaller.marshal(settings, new StreamResult(os));
        }
    }

    public void loadSettings() throws IOException {
        try (FileInputStream is = new FileInputStream(FILE_NAME)) {
            this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
        }
    }
}
kotlin
class Application {
    var settings = Settings()
    lateinit var marshaller: Marshaller
    lateinit var unmarshaller: Unmarshaller

    fun saveSettings() {
        FileOutputStream(FILE_NAME).use { os ->
            marshaller.marshal(settings, StreamResult(os))
        }
    }

    fun loadSettings() {
        FileInputStream(FILE_NAME).use { is ->
            settings = unmarshaller.unmarshal(StreamSource(is)) as Settings
        }
    }
}

支持的编组技术

JAXB

JAXB(Java Architecture for XML Binding)是 Java 标准的 XML 绑定技术。Spring 通过 Jaxb2Marshaller 提供支持。

xml
<oxm:jaxb2-marshaller id="marshaller">
    <oxm:class-to-be-bound name="com.example.Flight"/>
</oxm:jaxb2-marshaller>

XStream

XStream 是一个简单的库,用于将对象序列化为 XML 及其反向过程。它不需要任何映射,生成简洁的 XML。

安全警告

默认情况下,XStream 允许解组任意类,这可能导致不安全的 Java 序列化攻击。不建议使用 XStreamMarshaller 处理来自外部源(如 Web 流量)的 XML。如果必须使用,请设置 supportedClasses 属性以限制可处理的类。


补充教学

1. XML 还在流行吗?XML 编组的应用场景

虽然现代 Web 开发中 JSON 已成为主流,但 XML 编组在以下场景中依然至关重要:

  • Web Services (SOAP):SOAP 协议完全基于 XML,Spring OXM 可以很好地集成到 Spring Web Services 中。
  • 行业标准:金融(如 ISO 20022)、电信和政府系统仍广泛使用 XML 作为交互格式。
  • 配置文件:一些桌面或企业应用仍选择使用 XML 存储复杂的层次化配置。

2. JAXB 在 Java 11+ 中的变化

在 Java 8 之后,JAXB 已不再随 JDK 一起发布。如果你使用的是现代 JDK,你需要手动引入依赖:

  • Maven 坐标:早期是 javax.xml.bind:jaxb-api,现在已迁移到 Jakarta EE 命名空间 jakarta.xml.bind:jakarta.xml.bind-api
  • Spring 支持:Spring 6+ 全面支持 jakarta 命名空间。

3. XML 安全性 (XXE 攻击)

在处理 XML 时,安全性不容忽视。常见的威胁是 XML 外部实体(XXE)攻击

  • Spring 的保护:Spring 的编组器默认通常会禁用 DTD 声明和外部实体的处理,以降低风险。但如果你使用的是底层原始解析器,务必确保手动关闭相关功能,防止恶意 XML 导致的文件读取或 SSRF。

Based on Spring Framework.