21. 使用 O/XMap 器编组 XML

21.1 Introduction

在本章中,我们将描述 Spring 的对象/ XMLMap 支持。对象/ XMLMap(简称 O/XMap)是将 XML 文档与对象进行相互转换的操作。此转换过程也称为 XML 编组或 XML 序列化。本章可以互换使用这些术语。

在 O/XMap 领域中,* marshaller *负责将对象(图形)序列化为 XML。 * unmarshaller *以类似的方式将 XML 反序列化为对象图。该 XML 可以采用 DOM 文档,Importing 或输出流或 SAX 处理程序的形式。

使用 Spring 满足 O/XMap 需求的一些好处是:

21.1.1 易于配置

Spring 的 bean 工厂使配置封送程序变得容易,而无需构造 JAXB 上下文,JiBX 绑定工厂等。封送程序可以配置为应用程序上下文中的任何其他 bean。此外,许多编组人员都可以使用基于 XML 名称空间的配置,从而使配置更加简单。

21.1.2 一致的界面

Spring 的 O/XMap 通过两个全局接口进行操作:MarshallerUnmarshaller接口。这些抽象使您可以相对轻松地切换 O/XMap 框架,而对编组的类几乎不需要更改。这种方法的另一个好处是,可以利用每种技术的优势,以非介入方式使用混合匹配方法(例如,使用 JAXB 进行某些编组,而其他使用 XMLBeans 进行)进行 XML 编组。

21.1.3 一致的异常层次结构

Spring 提供了从底层 O/XMap 工具的异常到其自己的异常层次的转换,并以XmlMappingException作为根异常。可以预期,这些运行时异常包装了原始异常,因此不会丢失任何信息。

21.2 编组和解组

如引言中所述,* marshaller 将对象序列化为 XML,而 unmarshaller *将 XML 流反序列化为对象。在本节中,我们将描述用于此目的的两个 Spring 接口。

21.2.1 Marshaller

Spring 在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 表示形式,如下表所示。

Result implementation 包装 XML 表示形式
DOMResult org.w3c.dom.Node
SAXResult org.xml.sax.ContentHandler
StreamResult java.io.Filejava.io.OutputStreamjava.io.Writer

Note

尽管marshal()方法接受一个普通对象作为其第一个参数,但是大多数Marshaller实现无法处理任意对象。相反,必须将对象类 Map 到 Map 文件中,并用注解标记,在编组器中注册或具有公共 Base Class。请参阅本章的其他部分,以确定您选择的 O/X 技术如何 Management 此内容。

21.2.2 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(XMLImporting 抽象)中读取并返回读取的对象。与 Result 一样,Source 是具有三个具体实现的标记接口。每种包装不同的 XML 表示形式,如下表所示。

Source implementation 包装 XML 表示形式
DOMSource org.w3c.dom.Node
SAXSource org.xml.sax.InputSourceorg.xml.sax.XMLReader
StreamSource java.io.Filejava.io.InputStreamjava.io.Reader

即使有两个单独的编组接口(MarshallerUnmarshaller),Spring-WS 中的所有实现都在一个类中实现。这意味着您可以连接一个编组类,并将其称为applicationContext.xml中的编组和解组类。

21.2.3 XmlMappingException

Spring 使用XmlMappingException作为根异常将底层 O/XMap 工具中的异常转换为它自己的异常层次结构。可以预期,这些运行时异常包装了原始异常,因此不会丢失任何信息。

此外,MarshallingFailureExceptionUnmarshallingFailureException提供了编组和解组操作之间的区别,即使基础的 O/XMap 工具没有这样做。

O/XMap 异常层次结构如下图所示:

oxm exceptions

O/XMap 异常层次结构

21.3 使用 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 {
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(FILE_NAME);
            this.marshaller.marshal(settings, new StreamResult(os));
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    public void loadSettings() throws IOException {
        FileInputStream is = null;
        try {
            is = new FileInputStream(FILE_NAME);
            this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    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要求同时设置marshallerunmarshaller属性。我们可以使用以下applicationContext.xml来做到这一点:

<beans>
    <bean id="application" class="Application">
        <property name="marshaller" ref="castorMarshaller" />
        <property name="unmarshaller" ref="castorMarshaller" />
    </bean>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
</beans>

该应用程序上下文使用 Castor,但我们可以使用本章后面介绍的任何其他编组实例。注意,Castor 默认不需要任何进一步的配置,因此 bean 的定义非常简单。还要注意CastorMarshaller同时实现MarshallerUnmarshaller,因此我们可以在应用程序的marshallerunmarshaller属性中引用castorMarshaller bean。

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

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

21.4 XML 配置名称空间

可以使用 OXM 名称空间中的标签更简洁地配置 Marshallers。为了使这些标签可用,必须首先在 XML 配置文件的序言中引用适当的架构。请注意以下与“ oxm”相关的文本:

<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd">

当前,以下标签可用:

每个标签将在其各自的编组部分中进行说明。但是,作为一个示例,这是 JAXB2 编组器的配置可能如下所示:

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

21.5 JAXB

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

Spring 遵循第 21.2 节“ Marshaller 和 Unmarshaller”中描述的MarshallerUnmarshaller接口,将 JAXB 2.0 API 作为 XML 编组策略。相应的集成类位于org.springframework.oxm.jaxb包中。

21.5.1 Jaxb2Marshaller

Jaxb2Marshaller类同时实现 Spring MarshallerUnmarshaller接口。它需要一个上下文路径进行操作,您可以使用contextPath属性进行设置。上下文路径是用冒号(:)分隔的 Java 程序包名称的列表,其中包含模式派生的类。它还提供了classesToBeBound属性,该属性使您可以设置编组支持的类的数组。通过向 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子标签将要绑定的类的列表提供给编组:

<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>

可用的属性有:

Attribute Description Required
id 编组人员的 ID no
contextPath JAXB 上下文路径 no

21.6 Castor

Castor XMLMap 是一个开源 XML 绑定框架。它允许您将 Java 对象模型中包含的数据转换为 XML 文档或从 XML 文档转换。默认情况下,它不需要任何进一步的配置,尽管可以使用 Map 文件来更好地控制 Castor 的行为。

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

21.6.1 CastorMarshaller

与 JAXB 一样,CastorMarshaller实现MarshallerUnmarshaller接口。可以如下进行连接:

<beans>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
    ...
</beans>

21.6.2 Mapping

尽管可以依赖 Castor 的默认编组行为,但可能有必要对其进行更多控制。这可以使用 CastorMap 文件来完成。有关更多信息,请参阅Castor XMLMap

可以使用mappingLocation资源属性来设置 Map,该属性在下面用 Classpath 资源指示。

<beans>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
        <property name="mappingLocation" value="classpath:mapping.xml" />
    </bean>
</beans>

XML 配置名称空间

castor-marshaller标签配置org.springframework.oxm.castor.CastorMarshaller。这是一个例子:

<oxm:castor-marshaller id="marshaller" mapping-location="classpath:org/springframework/oxm/castor/mapping.xml"/>

通过指定 Map 文件的位置(通过mapping-location属性)或标识存在相应 XMLDescriptors 类的 Java POJO(通过target-classtarget-package属性),可以通过两种方式配置编组实例。后一种方法通常与从 XML 模式生成 XML 代码结合使用。

可用的属性有:

Attribute Description Required
id 编组人员的 ID no
encoding 用于从 XML 解组的编码 no
target-class POJO 的 Java 类名,该类具有 XML 类 Descriptors(通过代码生成生成) no
target-package Java 包名称,用于标识包含 POJO 及其对应的 Castor XMLDescriptors 类的包(由 XML 模式生成的代码生成) no
mapping-location Castor XMLMap 文件的位置 no

21.7 XMLBeans

XMLBeans 是一种 XML 绑定工具,具有完整的 XML Schema 支持,并提供完整的 XML Infoset 保真度。它与大多数其他 O/XMap 框架采用的方法不同,因为从 XML Schema 生成的所有类都源自XmlObject,并且其中包含 XML 绑定信息。

有关 XMLBeans 的更多信息,请参考XMLBeans 网站。 Spring-WS 集成类位于org.springframework.oxm.xmlbeans包中。

21.7.1 XmlBeansMarshaller

XmlBeansMarshaller同时实现MarshallerUnmarshaller接口。可以配置如下:

<beans>

    <bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
    ...

</beans>

Note

请注意,XmlBeansMarshaller只能封送XmlObject类型的对象,而不能封送每个java.lang.Object

XML 配置名称空间

xmlbeans-marshaller标签配置org.springframework.oxm.xmlbeans.XmlBeansMarshaller。这是一个例子:

<oxm:xmlbeans-marshaller id="marshaller"/>

可用的属性有:

Attribute Description Required
id 编组人员的 ID no
options 用于此编组器的 XmlOptions 的 bean 名称。通常为XmlOptionsFactoryBean定义 no

21.8 JiBX

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

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

21.8.1 JibxMarshaller

JibxMarshaller类同时实现MarshallerUnmarshaller接口。要进行操作,需要 Importing 要编组的类的名称,您可以使用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。如果要封送多个类,则必须使用不同的targetClass属性值配置多个JibxMarshaller

XML 配置名称空间

jibx-marshaller标签配置org.springframework.oxm.jibx.JibxMarshaller。这是一个例子:

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

可用的属性有:

Attribute Description Required
id 编组人员的 ID no
target-class 该编组的目标类 yes
bindingName 该编组使用的绑定名称 no

21.9 XStream

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

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

21.9.1 XStreamMarshaller

XStreamMarshaller不需要任何配置,可以直接在应用程序上下文中进行配置。要进一步自定义 XML,可以设置* alias map *,它由 Map 到类的字符串别名组成:

<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>

Warning

默认情况下,XStream 允许解组任意类,这会导致不安全的 Java 序列化效果。因此,不建议使用XStreamMarshaller来从外部来源(即 Web)解组 XML,因为这可能会导致安全漏洞*。

如果您选择使用XStreamMarshaller从外部源中解组 XML,请在XStreamMarshaller上设置supportedClasses属性,如下所示:

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

这样可以确保只有注册的类才有资格进行编组。

此外,您可以注册custom converters以确保只能解组受支持的类。除了显式支持应支持的域类的转换器之外,您可能还想添加CatchAllConverter作为列表中的最后一个转换器。结果,不会调用具有较低优先级和可能的安全漏洞的默认 XStream 转换器。

Note

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