20220507 7. Data Access - Marshalling XML by Using Object-XML Mappers

前言

文档地址

相关依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
</dependency>

介绍

本章描述了 Spring 的 Object-XML 映射支持。Object-XML 映射(简称 OX 映射)是将 XML 文档与对象相互转换的行为。此转换过程也称为 XML 编组或 XML 序列化。

在 OX 映射领域,编组器负责将对象(图)序列化为 XML。以类似的方式,解组器将 XML 反序列化为对象图。XML 可以采用 DOM 文档、输入或输出流或 SAX 处理程序的形式。

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

  • 易于配置
  • 一致的接口
  • 一致的异常层次结构

易于配置

Spring 的 bean 工厂可以轻松配置编组器,无需构建 JAXB 上下文、JiBX 绑定工厂等。您可以像配置应用上下文中的任何其他 bean 一样配置编组器。此外,许多编组器都可以使用基于 XML 命名空间的配置,从而使配置更加简单。

一致的接口

Spring 的 OX 映射通过两个全局接口运行:MarshallerUnmarshaller 。这些抽象使您可以相对轻松地切换 OX 映射框架,而对执行编组的类几乎不需要更改。这种方法还有一个额外的好处,它可以以一种非侵入性的方式使用混合匹配方法(例如,一些使用 JAXB 执行的一些编组,一些使用 XStream 执行的编组)进行 XML 编组,让您使用每个技术。

  • org.springframework.oxm.Marshaller
  • org.springframework.oxm.Unmarshaller

一致的异常层次结构

Spring 提供了从底层 OX 映射工具的异常到它自己的异常层次结构的转换,以 XmlMappingException 为根异常。这些运行时异常包装了原始异常,因此不会丢失任何信息。

MarshallerUnmarshaller

编组器将对象序列化为 XML,解组器将 XML 流反序列化为对象。

理解 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 表示,如下表所示:

结果实现 包装 XML 表示
DOMResult org.w3c.dom.Node
SAXResult org.xml.sax.ContentHandler
StreamResult java.io.Filejava.io.OutputStreamjava.io.Writer

理解 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 表示
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 中将其称为编组器和解组器。

理解 XmlMappingException

Spring 将来自底层 OX 映射工具的异常转换为它自己的异常层次结构,XmlMappingException 作为根异常。这些运行时异常包装了原始异常,因此不会丢失任何信息。

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

OX 映射异常层级如下图所示:

oxm 异常

使用 MarshallerUnmarshaller

在以下示例中,我们将 Spring 管理的应用程序的设置编组为 XML 文件。在以下示例中,我们使用一个简单的 JavaBean 来表示设置:

public class Settings {

    private boolean fooEnabled;

    public boolean isFooEnabled() {
        return fooEnabled;
    }

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

应用程序类使用这个 bean 来存储它的设置。除了 main 方法之外,该类还有两个方法: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 需要设置 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>

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

此示例程序生成以下 settings.xml 文件:

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

XML 配置命名空间

您可以使用 OXM 命名空间中的标签更简洁地配置编组器。要使这些标记可用,您必须首先在 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" 
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"> 

该 schema 使以下标签可用:

每个标签都在其各自的编组器部分进行了解释。但是,例如,JAXB2 编组器的配置可能类似于以下内容:

<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 编组策略,遵循 MarshallerUnmarshaller 接口。相应的集成类在 org.springframework.oxm.jaxb 包中。

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

下表描述了可用的属性:

属性 描述 是否必需
id 编组器的 ID
contextPath JAXB 上下文路径

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>

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

下表描述了可用的属性:

属性 描述 是否必需
id 编组器的 ID
target-class 编组器的目标类
bindingName 编组器使用的绑定名称

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 解组来自外部来源(即 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>

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

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

相关文章

php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念