# 5.使用Object-XML映射封装XML

## 5.1 简介

本章介绍了Spring的Object-XML Mapping支持。对象XML映射（简称O-X映射）是将XML文档与对象进行相互转换的动作。此转换过程也称为XML编组或XML序列化。本章可以互换使用这些术语。

在O-X映射领域中，marshaller负责将对象（图形）序列化为XML。以类似的方式，unmarshaller将XML反序列化为对象图。该XML可以采用DOM文档，输入或输出流或SAX处理程序的形式。

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

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

### 5.1.1 易于配置

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

### 5.1.2 一致的接口

Spring的O-X映射通过两个全局接口运行：Marshaller和Unmarshaller。这些抽象使您可以相对轻松地切换O-X映射框架，而进行编组的类几乎不需要更改。这种方法还有一个好处，就是可以以非介入方式使用混合匹配方法（例如，一些使用JAXB进行的编组和某些由Castor进行的编组）进行XML编组，从而让您充分利用每种方法的优势技术。

### 5.1.3 一致的异常层次结构

Spring提供了从底层O-X映射工具到XmlMappingException作为根异常的异常层次转换。这些运行时异常包装原始异常，因此不会丢失任何信息。

## 5.2 Marshaller和Unmarshaller

如引言中所述，封送器将对象序列化为XML，解组器将XML流反序列化为对象。 本节描述了用于此目的的两个Spring接口。

### 5.2.1 了解Marshaller

Spring在org.springframework.oxm.Marshaller接口背后抽象了所有编组操作，其主要方法如下：

```java
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.File, java.io.OutputStream, or java.io.Writer |

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

### 5.2.3 理解XmlMappingException

Spring使用XmlMappingException作为根异常，将基础O-X映射工具中的异常转换为它自己的异常层次结构。 这些运行时异常包装了原始异常，因此不会丢失任何信息。

此外，即使基础的O-X映射工具没有这样做，MarshallingFailureException和UnmarshallingFailureException也会在编组和解组操作之间进行区分。

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

![](https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/images/oxm-exceptions.png)

## 使用Marshaller和Unmarshaller

您可以在多种情况下使用Spring的OXM。 在下面的示例中，我们使用它来将Spring托管应用程序的设置作为XML文件进行编组。 在下面的示例中，我们使用一个简单的JavaBean来表示设置：

```java
public class Settings {

    private boolean fooEnabled;

    public boolean isFooEnabled() {
        return fooEnabled;
    }

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

应用程序类使用此bean存储其设置。 除了主要方法之外，该类还有两个方法：saveSettings（）将settings Bean保存到名为settings.xml的文件中，loadSettings（）再次加载这些设置。 下面的main（）方法构造一个Spring应用程序上下文并调用这两个方法：

```java
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();
    }
}
```

该应用程序需要同时设置封送程序和取消封送程序属性。 我们可以使用以下applicationContext.xml来做到这一点：

```markup
<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同时实现了Marshaller和Unmarshaller，因此我们可以在应用程序的marshaller和unmarshaller属性中引用castorMarshaller bean。

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

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

## 5.4 XML配置命名空间

您可以使用OXM名称空间中的标签来更简洁地配置编组器。 要使这些标签可用，您必须首先在XML配置文件的序言中引用适当的架构。 以下示例显示了如何执行此操作：

```markup
<?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">
```

当前，该模式使以下元素可用：

jaxb2-marshaller

jibx-marshaller

castor-marshaller

每个标签均在其各自的编组部分中进行了说明。 但是，作为示例，JAXB2编组器的配置可能类似于以下内容：

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

## 5.5 JAXB

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

遵循Marshaller和Unmarshaller中描述的Marshaller和Unmarshaller接口，Spring支持JAXB 2.0 API作为XML编组策略。相应的集成类位于org.springframework.oxm.jaxb包中。

### 5.5.1 使用Jaxb2Marshaller

Jaxb2Marshaller类实现了Spring的Marshaller和Unmarshaller接口。它需要上下文路径才能运行。您可以通过设置contextPath属性来设置上下文路径。上下文路径是冒号分隔的Java程序包名称的列表，其中包含模式派生的类。它还提供了classesToBeBound属性，该属性使您可以设置编组支持的类的数组。通过向Bean指定一个或多个模式资源来执行模式验证，如以下示例所示：

```markup
<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，如以下示例所示：

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

或者，您可以使用要绑定的子类元素提供绑定到编组器的类的列表：

```markup
<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          | The ID of the marshaller | No       |
| contextPath | The JAXB Context path    | No       |

## 5.6 Castor

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

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

### 5.6.1 使用CastorMarshaller

与JAXB一样，CastorMarshaller也实现Marshaller和Unmarshaller接口。 可以按以下方式进行连接：

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

## 5.6.2 Mapping

尽管可以依赖Castor的默认编组行为，但可能需要对其进行更多控制。 您可以通过使用Castor映射文件来获得更多控制。 有关更多信息，请参见Castor XML映射。

您可以通过使用mappingLocation资源属性来设置映射，在以下示例中使用类路径资源来指示：

```markup
<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，如以下示例所示：

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

您可以通过两种方式配置marshaller实例：通过指定映射文件的位置（通过mapping-location属性）或通过标识Java POJO（通过target-class或target-package属性）来确定存在其对应XML的Java POJO。 描述符类。 后一种方法通常与从XML模式生成XML代码结合使用。

下表描述了可用的属性：

| Attribute        | Description                                                                                                                                                                     | Required |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| id               | The ID of the marshaller                                                                                                                                                        | No       |
| encoding         | The encoding to use for unmarshalling from XML                                                                                                                                  | No       |
| target-class     | A Java class name for a POJO for which an XML class descriptor is available (as generated through code generation)                                                              | No       |
| target-package   | A Java package name that identifies a package that contains POJOs and their corresponding Castor XML descriptor classes (as generated through code generation from XML schemas) | No       |
| mapping-location | Location of a Castor XML mapping file                                                                                                                                           | No       |

## 5.7 JiBX

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

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

### 5.7.1 使用JibxMarshaller

JibxMarshaller类同时实现Marshaller和Unmarshaller接口。 要进行操作，需要输入要编组的类的名称，您可以使用targetClass属性进行设置。 （可选）您可以通过设置bindingName属性来设置绑定名称。 在下面的示例中，我们绑定了Flights类：

```markup
<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，如以下示例所示：

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

## 5.8 XStream

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

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

### 5.8.1 使用XStreamMarshaller

XStreamMarshaller不需要任何配置，可以直接在应用程序上下文中进行配置。 要进一步自定义XML，可以设置一个别名映射，该映射由映射到类的字符串别名组成，如以下示例所示：

```markup
<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属性，如以下示例所示：

```markup
<bean id =“ xstreamMarshaller” class =“ org.springframework.oxm.xstream.XStreamMarshaller”>
    <property name =“ supportedClasses” value =“ org.springframework.oxm.xstream.Flight” />
    ...
</ bean>
```

> 这样做可以确保只有注册的班级才有资格进行编组。
>
> 此外，您可以注册自定义转换器，以确保只能解组受支持的类。除了明确支持应支持的域类的转换器之外，您可能还想添加CatchAllConverter作为列表中的最后一个转换器。结果，不会调用具有较低优先级和可能的安全漏洞的默认XStream转换器。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flydean.com/spring-framework-documentation5/dataaccess/5.object-xml-mappers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
