21. 使用 O/X Mappers 编组 XML

21.1 简介

在本章中,我们将描述 Spring 的 Object/XML Mapping 支持。 Object/XML Mapping,或简称为 O/X mapping,是将 XML 文档转换为 object 和从 object 转换 XML 文档的行为。此转换 process 也称为 XML 编组或 XML 序列化。本章可互换使用这些术语。

在 O/X mapping 的字段中,marshaller 负责将 object(图形)序列化为 XML。以类似的方式,unmarshaller 将 XML 反序列化为 object 图。此 XML 可以采用 DOM 文档,输入或输出流或 SAX 处理程序的形式。

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

21.1.1 易于配置

Spring 的 bean 工厂可以轻松配置 marshallers,无需构建 JAXB context,JiBX binding 工厂等。可以将 marshallers 配置为 application context 中的任何其他 bean。此外,XML namespace-based configuration 可用于许多 marshallers,使 configuration 更简单。

21.1.2 一致的接口

Spring 的 O/X 映射通过两个 global 接口运行:MarshallerUnmarshaller接口。这些抽象允许您相对容易地切换 O/X 映射框架,在进行编组的 classes 上几乎不需要进行任何更改。这种方法的另一个好处是可以利用方法进行 XML 编组(e.g. 使用 JAXB 执行某些编组,其他使用 XMLBeans 执行编组),利用每种技术的优势。

21.1.3 一致的 exception 层次结构

Spring 提供从基础 O/X 映射工具的 exceptions 到其自己的 exception 层次结构的转换,其中XmlMappingException作为根 exception。可以预料,这些运行时 exceptions 会包装原始的 exception,因此不会丢失任何信息。

21.2 Marshaller 和 Unmarshaller

正如介绍中所述,marshaller 将 object 序列化为 XML,而 unmarshaller 将 XML 流反序列化为 object。在本节中,我们将描述用于此目的的两个 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接口有一个 main 方法,它将给定的 object 封送到给定的javax.xml.transform.Result。 Result 是一个标记接口,基本上表示 XML 输出抽象:具体的 implementations 包含各种 XML 表示,如下面的 table 所示。

结果 implementation包装 XML 表示
DOMResultorg.w3c.dom.Node
SAXResultorg.xml.sax.ContentHandler
StreamResultjava.io.Filejava.io.OutputStreamjava.io.Writer

尽管marshal()方法接受普通的 object 作为其第一个参数,但大多数Marshaller implementations 都无法处理任意的 objects。相反,object class 必须映射到映射文件中,标记为 annotation,向 marshaller 注册,或者具有 common base class。请参阅本章的其他部分,以确定您选择的 O/X 技术如何管理它。

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(XML 输入抽象)中读取,并返回 object 读取。与 Result 一样,Source 是一个标记界面,具有三个具体的 implementation。每个包装一个不同的 XML 表示,如下面的 table 所示。

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

即使有两个单独的编组接口(MarshallerUnmarshaller),Spring-WS 中的所有_implement 都在一个 class 中实现。这意味着您可以连接一个 marshaller class 并将其作为 marshaller 和 unmarshaller 引用到applicationContext.xml中。

21.2.3 XmlMappingException

Spring 将 exceptions 从底层的 O/X 映射工具转换为自己的 exception 层次结构,并将XmlMappingException作为根 exception。可以预料,这些运行时 exceptions 会包装原始的 exception,因此不会丢失任何信息。

此外,MarshallingFailureExceptionUnmarshallingFailureException提供了编组和解组操作之间的区别,即使底层的 O/X 映射工具不这样做。

O/X Mapping exception 层次结构如下图所示:

oxm exceptions

O/X 映射 exception 层次结构

21.3 使用 Marshaller 和 Unmarshaller

Spring 的 OXM 可用于各种情况。在下面的示例中,我们将使用它将 Spring-managed application 的设置编组为 XML 文件。我们将使用一个简单的 JavaBean 来表示设置:

public class Settings {

    private boolean fooEnabled;

    public boolean isFooEnabled() {
        return fooEnabled;
    }

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

application class 使用此 bean 来存储其设置。除了 main 方法之外,class 还有两个方法:saveSettings()将设置 bean 保存到名为settings.xml的文件中,loadSettings()再次加载这些设置。 main()方法构造一个 Spring application context,并_call 这两个方法。

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需要设置marshallerunmarshallerproperty。我们可以使用以下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>

此 application context 使用 Castor,但我们可以使用本章后面介绍的任何其他 marshaller 实例。请注意,默认情况下 Castor 不需要任何进一步的 configuration,因此 bean 定义相当简单。另请注意,CastorMarshaller同时实现了MarshallerUnmarshaller,因此我们可以在 application 的marshallerunmarshallerproperty 中引用castorMarshaller bean。

此 sample application 生成以下settings.xml文件:

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

21.4 XML configuration 命名空间

可以使用来自 OXM 名称空间的标签更简洁地配置 Marshallers。要使这些标记可用,必须首先在 XML configuration 文件的前导码中引用相应的 schema。请注意下面的'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 编组器的 configuration 可能如下所示:

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

21.5 JAXB

JAXB binding 编译器将 W3C XML Schema 转换为一个或多个 Java classes,一个jaxb.properties文件,可能还有一些资源 files。 JAXB 还提供了一种从带注释的 Java classes 生成 schema 的方法。

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

21.5.1 Jaxb2Marshaller

Jaxb2Marshaller class 实现 Spring MarshallerUnmarshaller接口。它需要 context 路径才能运行,您可以使用contextPath property 进行设置。 context 路径是冒号列表(:)分隔的 Java 包名称,包含 schema 派生的 classes。它还提供classesToBeBound property,它允许您设置 marshaller 支持 class 的_arlass。Schema 验证通过指定一个来执行或更多 schema 资源到 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 configuration 命名空间

jaxb2-marshaller标签配置org.springframework.oxm.jaxb.Jaxb2Marshaller。这是一个 example:

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

或者,要绑定的 classes 列表可以通过class-to-be-bound child 标记提供给编组器:

<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 的身份没有
contextPathJAXB Context 路径没有

21.6 Castor

Castor XML mapping 是一个开源的 XML binding framework。它允许您将 java object model into/from 中包含的数据转换为 XML 文档。默认情况下,它不需要任何进一步的 configuration,但可以使用映射文件来更好地控制 Castor 的行为。

有关 Castor 的更多信息,请参阅Castor web 网站。 Spring integration classes 位于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 制图

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

可以使用mappingLocation resource property 设置映射,如下所示,使用 classpath 资源。

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

XML configuration 命名空间

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

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

marshaller 实例可以通过两种方式配置,通过指定映射文件的位置(通过mapping-location property),或通过标识存在相应 XML 描述符 classes 的 Java POJO(通过target-classtarget-packageproperties)。后一种方法通常与 XML 模式的 XML code 生成结合使用。

可用属性包括:

属性描述需要
idmarshaller 的身份没有
encoding用于从 XML 解组的编码没有
target-classPOJO 的 Java class name,XML class 描述符可用(通过 code 生成生成)没有
target-package一个 Java 包 name,用于标识包含 POJO 的包及其对应的 Castor XML 描述符 classes(通过从 XML 模式生成 code 生成)没有
mapping-locationCastor XML 映射文件的位置没有

21.7 XMLBeans

XMLBeans 是一个 XML binding 工具,具有完整的 XML Schema 支持,并提供完整的 XML Infoset 保真度。它采用与大多数其他 O/X 映射框架不同的方法,因为从 XML Schema 生成的所有 class 都是从XmlObject派生的,并且在其中包含 XML binding 信息。

有关 XMLBeans 的更多信息,请参阅XMLBeans web 站点。 Spring-WS integration classes 位于org.springframework.oxm.xmlbeans包中。

21.7.1 XmlBeansMarshaller

XmlBeansMarshaller实现了MarshallerUnmarshaller接口。它可以配置如下:

<beans>

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

</beans>

请注意,XmlBeansMarshaller只能编组XmlObject类型的 objects,而不是每个java.lang.Object

XML configuration 命名空间

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

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

可用属性包括:

属性描述需要
idmarshaller 的身份没有
options要用于此编组程序的 XmlOptions 的 bean name。通常是XmlOptionsFactoryBean定义没有

21.8 JiBX

JiBX framework 提供了类似于 JDO 为 ORM 提供的解决方案:binding 定义定义了 Java objects 如何转换为 XML 或从 XML 转换的规则。在准备了 binding 并编译 classes 之后,JiBX binding 编译器增强了 class files,并添加了 code 来处理从或 XML 转换 classes 的实例。

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

21.8.1 JibxMarshaller

JibxMarshaller class 实现MarshallerUnmarshaller接口。要进行操作,需要 class 的 name 编组,您可以使用targetClass property 进行设置。 (可选)您可以使用bindingName property 设置 binding name。在下一个 sample 中,我们绑定Flights class:

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

配置为单个 class。如果要编组多个 classes,则必须使用不同的targetClass property 值配置多个JibxMarshaller

XML configuration 命名空间

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

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

可用属性包括:

属性描述需要
idmarshaller 的身份没有
target-class这个编组的目标 class
bindingName这个编组使用的 binding name没有

21.9 XStream

XStream 是一个简单的 library,可以将 objects 序列化为 XML,然后再返回。它不需要任何映射,并生成干净的 XML。

有关 XStream 的更多信息,请参阅XStream web 网站。 Spring integration classes 位于org.springframework.oxm.xstream包中。

21.9.1 XStreamMarshaller

XStreamMarshaller不需要任何 configuration,可以直接在 application context 中配置。要进一步自定义 XML,可以设置 analias map,它由映射到 classes 的 string 别名组成:

<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 允许任意 classes 被解组,这可能导致不安全的 Java 序列化效果。因此,不建议使用XStreamMarshaller来解析来自外部源(i.e.Web)的 XML,因为这可能导致安全漏洞。

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

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

这将确保只有已注册的 classes 才有资格进行解组。

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

请注意,XStream 是 XML 序列化 library,而不是数据 binding library。因此,它具有有限的命名空间支持。因此,它不适合在 Web services 中使用。

Updated at: 9 months ago
20.5.5. 使用 JTA transaction management 设置 JPATable of contentVI. Web