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 表示形式
DOMResultorg.w3c.dom.Node
SAXResultorg.xml.sax.ContentHandler
StreamResultjava.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 表示形式
DOMSourceorg.w3c.dom.Node
SAXSourceorg.xml.sax.InputSourceorg.xml.sax.XMLReader
StreamSourcejava.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>

可用的属性有:

AttributeDescriptionRequired
id编组人员的 IDno
contextPathJAXB 上下文路径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 代码结合使用。

可用的属性有:

AttributeDescriptionRequired
id编组人员的 IDno
encoding用于从 XML 解组的编码no
target-classPOJO 的 Java 类名,该类具有 XML 类 Descriptors(通过代码生成生成)no
target-packageJava 包名称,用于标识包含 POJO 及其对应的 Castor XMLDescriptors 类的包(由 XML 模式生成的代码生成)no
mapping-locationCastor 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"/>

可用的属性有:

AttributeDescriptionRequired
id编组人员的 IDno
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"/>

可用的属性有:

AttributeDescriptionRequired
id编组人员的 IDno
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 服务中使用。