跳到主要内容
版本:6.2.3

使用对象-XML 映射器进行 XML 序列化

ChatGPT-4o-mini 中英对照 Marshalling XML by Using Object-XML Mappers

引言​

本章描述了 Spring 的对象-XML 映射支持。对象-XML 映射(简称 O-X 映射)是将 XML 文档转换为对象及其反向转换的过程。这个转换过程也被称为 XML 编组,或 XML 序列化。本章将这些术语交替使用。

在 O-X 映射领域,marshaller 负责将对象(图)序列化为 XML。类似地,unmarshaller 将 XML 反序列化为对象图。这个 XML 可以是 DOM 文档、输入或输出流,或 SAX 处理器的形式。

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

配置的简易性​

Spring 的 bean 工厂使得配置 marshaller 变得简单,无需构造 JAXB 上下文、JiBX 绑定工厂等。您可以像配置应用程序上下文中的其他 bean 一样配置 marshaller。此外,基于 XML 命名空间的配置可用于多个 marshaller,使配置变得更加简单。

一致的接口​

Spring 的 O-X 映射通过两个全局接口操作:Marshaller 和 Unmarshaller。这些抽象使您能够相对轻松地切换 O-X 映射框架,对执行 marshalling 的类几乎不需要进行更改。这种方法的额外好处是能够以非侵入的方式进行 XML marshalling,采用混合搭配的方法(例如,一些 marshalling 使用 JAXB 执行,另一些则使用 XStream),让您能够利用每种技术的优势。

一致的异常层次结构​

Spring 提供了将底层 O-X 映射工具的异常转换为其自身异常层次结构的功能,以 XmlMappingException 作为根异常。这些运行时异常包装了原始异常,以确保没有信息丢失。

Marshaller 和 Unmarshaller​

如 介绍 中所述,marshaller 将对象序列化为 XML,而 unmarshaller 将 XML 流反序列化为对象。本节描述了为此目的使用的两个 Spring 接口。

理解 Marshaller​

Spring 将所有的 marshalling 操作抽象到 org.springframework.oxm.Marshaller 接口后面,其主要方法如下:

public interface Marshaller {

/**
* Marshal the object graph with the given root into the provided Result.
*/
void marshal(Object graph, Result result) throws XmlMappingException, IOException;
}

Marshaller 接口有一个主要方法,该方法将给定对象编组到给定的 javax.xml.transform.Result。结果是一个标记接口,基本上代表 XML 输出抽象。具体实现包装各种 XML 表示,如下表所示:

结果实现包装 XML 表示
DOMResultorg.w3c.dom.Node
SAXResultorg.xml.sax.ContentHandler
StreamResultjava.io.File、java.io.OutputStream 或 java.io.Writer
备注

虽然 marshal() 方法接受一个普通对象作为其第一个参数,但大多数 Marshaller 实现无法处理任意对象。相反,一个对象类必须在映射文件中映射,标记为注解,注册到 marshaller,或者具有一个公共基类。请参考本章后面的部分以确定您的 O-X 技术是如何管理这一点的。

理解 Unmarshaller​

类似于 Marshaller,我们有 org.springframework.oxm.Unmarshaller 接口,以下列表显示了该接口:

public interface Unmarshaller {

/**
* Unmarshal the given provided Source into an object graph.
*/
Object unmarshal(Source source) throws XmlMappingException, IOException;
}

这个接口还有一个方法,它从给定的 javax.xml.transform.Source(一个 XML 输入抽象)中读取并返回读取的对象。与 Result 一样,Source 是一个标记接口,它有三个具体实现。每个实现包装了不同的 XML 表示,如下表所示:

源实现包装 XML 表示
DOMSourceorg.w3c.dom.Node
SAXSourceorg.xml.sax.InputSource 和 org.xml.sax.XMLReader
StreamSourcejava.io.File、java.io.InputStream 或 java.io.Reader

尽管有两个独立的 marshalling 接口(Marshaller 和 Unmarshaller),但 Spring-WS 中的所有实现都在一个类中实现了这两个接口。这意味着您可以在 applicationContext.xml 中连接一个 marshaller 类,并将其同时作为 marshaller 和 unmarshaller 使用。

理解 XmlMappingException​

Spring 将底层 O-X 映射工具的异常转换为其自己的异常层次结构,以 XmlMappingException 作为根异常。这些运行时异常包装了原始异常,以确保不会丢失任何信息。

此外,MarshallingFailureException 和 UnmarshallingFailureException 在 marshalling 和 unmarshalling 操作之间提供了区分,尽管底层的 O-X 映射工具并没有这样做。

O-X 映射异常层次结构如下面的图所示:

oxm exceptions

使用 Marshaller 和 Unmarshaller​

您可以在各种情况下使用 Spring 的 OXM。在以下示例中,我们使用它将 Spring 管理的应用程序的设置序列化为 XML 文件。在以下示例中,我们使用一个简单的 JavaBean 来表示设置:

public class Settings {

private boolean fooEnabled;

public boolean isFooEnabled() {
return fooEnabled;
}

public void setFooEnabled(boolean fooEnabled) {
this.fooEnabled = fooEnabled;
}
}

该应用程序类使用这个 bean 来存储其设置。除了一个主方法,该类还有两个方法:saveSettings() 将设置 bean 保存到名为 settings.xml 的文件中,loadSettings() 再次加载这些设置。以下 main() 方法构建了一个 Spring 应用程序上下文并调用这两个方法:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

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));
}
}

public static void main(String[] args) throws IOException {
ApplicationContext appContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
Application application = (Application) appContext.getBean("application");
application.saveSettings();
application.loadSettings();
}
}

Application 需要同时设置 marshaller 和 unmarshaller 属性。我们可以通过使用以下 applicationContext.xml 来实现:

<beans>
<bean id="application" class="Application">
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
</beans>

此应用程序上下文使用 XStream,但我们可以使用本章后面描述的任何其他 marshaller 实例。请注意,默认情况下,XStream 不需要任何进一步的配置,因此 bean 定义相对简单。还要注意,XStreamMarshaller 实现了 Marshaller 和 Unmarshaller,因此我们可以在应用程序的 marshaller 和 unmarshaller 属性中引用 xstreamMarshaller bean。

该示例应用程序生成以下 settings.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>

XML 配置命名空间​

您可以通过使用 OXM 命名空间中的标签更简洁地配置 marshallers。要使这些标签可用,您必须首先在 XML 配置文件的前言中引用适当的模式。以下示例演示了如何做到这一点:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm" // <1>
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/oxm
https://www.springframework.org/schema/oxm/spring-oxm.xsd"> // <2>
  • 引用 oxm 模式。

  • 指定 oxm 模式位置。

该模式提供以下元素:

每个标签在其各自的 marshaller 部分都有解释。作为一个例子,JAXB2 marshaller 的配置可能类似于以下内容:

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>

JAXB​

JAXB 绑定编译器将 W3C XML Schema 转换为一个或多个 Java 类、一个 jaxb.properties 文件,以及可能的一些资源文件。JAXB 还提供了一种从注释的 Java 类生成模式的方法。

Spring 支持 JAXB 2.0 API 作为 XML 序列化策略,遵循 Marshaller and Unmarshaller 中描述的 Marshaller 和 Unmarshaller 接口。相应的集成类位于 org.springframework.oxm.jaxb 包中。

使用 Jaxb2Marshaller​

Jaxb2Marshaller 类实现了 Spring 的 Marshaller 和 Unmarshaller 接口。它需要一个上下文路径来操作。您可以通过设置 contextPath 属性来设置上下文路径。上下文路径是一个由冒号分隔的 Java 包名称列表,这些包包含模式派生类。它还提供了一个 classesToBeBound 属性,允许您设置一个要由 marshaller 支持的类数组。模式验证是通过向 bean 指定一个或多个模式资源来执行的,如下例所示:

<beans>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>org.springframework.oxm.jaxb.Flight</value>
<value>org.springframework.oxm.jaxb.Flights</value>
</list>
</property>
<property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
</bean>

...

</beans>

XML 配置命名空间​

jaxb2-marshaller 元素配置一个 org.springframework.oxm.jaxb.Jaxb2Marshaller,如下例所示:

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>

或者,您可以通过使用 class-to-be-bound 子元素提供要绑定到 marshaller 的类列表:

<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Airport"/>
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Flight"/>
...
</oxm:jaxb2-marshaller>

以下表格描述了可用的属性:

属性描述必需
idmarshaller 的 ID否
contextPathJAXB 上下文路径否

JiBX​

JiBX 框架提供了一种类似于 Hibernate 为 ORM 提供的解决方案:绑定定义定义了 Java 对象如何转换为 XML 或从 XML 转换的规则。在准备好绑定并编译类之后,JiBX 绑定编译器增强了类文件,并添加了处理将类实例从 XML 转换或转换为 XML 的代码。

有关 JiBX 的更多信息,请参阅 JiBX 网站。Spring 集成类位于 org.springframework.oxm.jibx 包中。

使用 JibxMarshaller​

JibxMarshaller 类实现了 Marshaller 和 Unmarshaller 接口。要操作,它需要要序列化的类的名称,您可以通过设置 targetClass 属性来指定。可选地,您可以通过设置 bindingName 属性来设置绑定名称。在以下示例中,我们绑定了 Flights 类:

<beans>
<bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass">org.springframework.oxm.jibx.Flights</property>
</bean>
...
</beans>

一个 JibxMarshaller 被配置为单个类。如果您想要处理多个类,您必须配置多个 JibxMarshaller 实例,并为它们设置不同的 targetClass 属性值。

XML 配置命名空间​

jibx-marshaller 标签配置一个 org.springframework.oxm.jibx.JibxMarshaller,如下例所示:

<oxm:jibx-marshaller id="marshaller" target-class="org.springframework.ws.samples.airline.schema.Flight"/>

以下表格描述了可用的属性:

属性描述必需
idmarshaller 的 ID否
target-class此 marshaller 的目标类是
bindingName此 marshaller 使用的绑定名称否

XStream​

XStream 是一个简单的库,用于将对象序列化为 XML 并再反序列化回来。它不需要任何映射,并生成干净的 XML。

有关 XStream 的更多信息,请参见 XStream 网站。Spring 集成类位于 org.springframework.oxm.xstream 包中。

使用 XStreamMarshaller​

XStreamMarshaller 不需要任何配置,可以直接在应用上下文中进行配置。要进一步自定义 XML,您可以设置一个别名映射,该映射由字符串别名映射到类,如以下示例所示:

<beans>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
</props>
</property>
</bean>
...
</beans>
注意

默认情况下,XStream 允许任意类被反序列化,这可能导致不安全的 Java 序列化效果。因此,我们不建议使用 XStreamMarshaller 从外部源(即网络)反序列化 XML,因为这可能导致安全漏洞。

如果您选择使用 XStreamMarshaller 从外部源反序列化 XML,请在 XStreamMarshaller 上设置 supportedClasses 属性,如下例所示:

<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="supportedClasses" value="org.springframework.oxm.xstream.Flight"/>
...
</bean>

这样可以确保只有注册的类可以进行反序列化。

此外,您可以注册 自定义转换器,以确保只有您支持的类可以被反序列化。您可能希望在列表中添加一个 CatchAllConverter 作为最后一个转换器,除了明确支持应被支持的领域类的转换器。这样,默认的 XStream 转换器(优先级较低且可能存在安全漏洞)将不会被调用。

备注

请注意,XStream 是一个 XML 序列化库,而不是数据绑定库。因此,它对命名空间的支持有限。因此,它在 Web 服务中的使用相对不适合。