跳到主要内容

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

一致的异常层次结构

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

MarshallerUnmarshaller

介绍 中所述,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;
}
java

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

结果实现包装 XML 表示
DOMResultorg.w3c.dom.Node
SAXResultorg.xml.sax.ContentHandler
StreamResultjava.io.Filejava.io.OutputStreamjava.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;
}
java

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

源实现包装 XML 表示
DOMSourceorg.w3c.dom.Node
SAXSourceorg.xml.sax.InputSourceorg.xml.sax.XMLReader
StreamSourcejava.io.Filejava.io.InputStreamjava.io.Reader

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

理解 XmlMappingException

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

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

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

oxm exceptions

使用 MarshallerUnmarshaller

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

public class Settings {

private boolean fooEnabled;

public boolean isFooEnabled() {
return fooEnabled;
}

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

该应用程序类使用这个 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();
}
}
java

Application 需要同时设置 marshallerunmarshaller 属性。我们可以通过使用以下 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>
xml

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

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

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

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>
xml
  • 引用 oxm 模式。

  • 指定 oxm 模式位置。

该模式提供以下元素:

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

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

JAXB

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

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

使用 Jaxb2Marshaller

Jaxb2Marshaller 类实现了 Spring 的 MarshallerUnmarshaller 接口。它需要一个上下文路径来操作。您可以通过设置 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

XML 配置命名空间

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

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

或者,您可以通过使用 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>
xml

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

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

JiBX

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

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

使用 JibxMarshaller

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

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

一个 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"/>
xml

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

属性描述必需
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>
xml
注意

默认情况下,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>
xml

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

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

备注

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