使用对象-XML映射器编组XML
简介
本章描述 Spring 的对象-XML 映射支持。对象-XML 映射(简称 O-X 映射)是将 XML 文档与对象进行相互转换的操作。此转换过程也称为 XML 编组(XML Marshalling)或 XML 序列化(XML Serialization)。本章交替使用这些术语。
在 O-X 映射领域中,marshaller(编组器)负责将对象(图)序列化为 XML。类似地,unmarshaller(解组器)将 XML 反序列化为对象图。此 XML 可以采用 DOM 文档、输入或输出流或 SAX handler 的形式。
使用 Spring 处理 O/X 映射需求的一些优势包括:
配置简单
Spring 的 bean factory 使配置 marshaller 变得简单,无需构建 JAXB context、JiBX binding factory 等。您可以像配置应用上下文中的任何其他 bean 一样配置 marshaller。此外,许多 marshaller 支持基于 XML 命名空间的配置,使配置更加简单。
接口一致
Spring 的 O-X 映射通过两个全局接口进行操作:Marshaller
和 Unmarshaller
。这些抽象使您能够相对轻松地切换 O-X 映射框架,而无需对执行编组的类进行很少或无需更改。这种方法还有一个额外的好处,即可以通过一种非侵入式的方式进行 XML 编组,采用混合搭配的方法(例如,一些编组使用 JAXB 执行,一些使用 XStream 执行),让您可以使用每种技术的优势。
Marshaller
和 Unmarshaller
如简介中所述,marshaller 将对象序列化为 XML,unmarshaller 将 XML 流反序列化为对象。本节描述用于此目的的两个 Spring 接口。
理解 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
。Result 是一个标记接口,它基本上代表了一个 XML 输出抽象。具体实现封装了各种 XML 表示形式,如下表所示:
Result 实现 | 封装的 XML 表示形式 |
---|---|
|
|
|
|
|
|
尽管 marshal() 方法接受一个普通对象作为其第一个参数,但大多数 Marshaller 实现无法处理任意对象。相反,对象类必须在映射文件中进行映射,用注解标记,向 marshaller 注册,或者具有公共基类。请参阅本章后面的部分,了解您的 O-X 技术如何管理此事。 |
理解 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 表示形式,如下表所示:
Source 实现 | 封装的 XML 表示形式 |
---|---|
|
|
|
|
|
|
即使有两个单独的编组接口(Marshaller
和 Unmarshaller
),Spring-WS 中的所有实现都在一个类中实现两者。这意味着您可以在 applicationContext.xml
中配置一个 marshaller 类,并将其同时用作 marshaller 和 unmarshaller。
使用 Marshaller
和 Unmarshaller
您可以在各种情况下使用 Spring 的 OXM。在以下示例中,我们使用它将 Spring 管理的应用设置编组为 XML 文件。在以下示例中,我们使用一个简单的 JavaBean 表示设置:
-
Java
-
Kotlin
public class Settings {
private boolean fooEnabled;
public boolean isFooEnabled() {
return fooEnabled;
}
public void setFooEnabled(boolean fooEnabled) {
this.fooEnabled = fooEnabled;
}
}
class Settings {
var isFooEnabled: Boolean = false
}
应用类使用此 bean 存储其设置。除了一个 main 方法之外,该类还有两个方法:saveSettings()
将设置 bean 保存到名为 settings.xml
的文件,loadSettings()
再次加载这些设置。以下 main()
方法构建 Spring 应用上下文并调用这两个方法:
-
Java
-
Kotlin
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();
}
}
class Application {
lateinit var marshaller: Marshaller
lateinit var unmarshaller: Unmarshaller
fun saveSettings() {
FileOutputStream(FILE_NAME).use { outputStream -> marshaller.marshal(settings, StreamResult(outputStream)) }
}
fun loadSettings() {
FileInputStream(FILE_NAME).use { inputStream -> settings = unmarshaller.unmarshal(StreamSource(inputStream)) as Settings }
}
}
private const val FILE_NAME = "settings.xml"
fun main(args: Array<String>) {
val appContext = ClassPathXmlApplicationContext("applicationContext.xml")
val application = appContext.getBean("application") as Application
application.saveSettings()
application.loadSettings()
}
Application
需要同时设置 marshaller
和 unmarshaller
属性。我们可以使用以下 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,但我们可以使用本章后面描述的任何其他 marshaller 实例。请注意,默认情况下,XStream 不需要任何进一步配置,因此 bean 定义相当简单。还要注意,XStreamMarshaller
同时实现了 Marshaller
和 Unmarshaller
接口,因此我们可以在应用的 marshaller
和 unmarshaller
属性中引用同一个 xstreamMarshaller
bean。
此示例应用生成以下 settings.xml
文件:
<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>
XML 配置命名空间
您可以使用 OXM 命名空间中的标签更简洁地配置 marshaller。要使这些标签可用,您必须首先在 XML 配置文件的前言中引用相应的 schema。以下示例展示了如何操作:
<?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" (1)
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"> (2)
1 | 引用 oxm schema。 |
2 | 指定 oxm schema 位置。 |
此 schema 提供以下元素:
每个标签在其各自 marshaller 的部分中进行解释。例如,JAXB2 marshaller 的配置可能类似于以下内容:
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>
JAXB
JAXB binding compiler 将 W3C XML Schema 转换为一个或多个 Java 类、一个 jaxb.properties
文件,以及可能的一些资源文件。JAXB 还提供了一种从带注解的 Java 类生成 schema 的方法。
Spring 支持 JAXB 2.0 API 作为 XML 编组策略,遵循Marshaller
和 Unmarshaller
中描述的 Marshaller
和 Unmarshaller
接口。相应的集成类位于 org.springframework.oxm.jaxb
包中。
使用 Jaxb2Marshaller
Jaxb2Marshaller
类实现了 Spring 的 Marshaller
和 Unmarshaller
两个接口。它需要一个 context path 才能操作。您可以通过设置 contextPath
属性来设置 context path。context path 是一个包含 schema 派生类的以冒号分隔的 Java 包名列表。它还提供了一个 classesToBeBound
属性,允许您设置 marshaller 支持的类数组。通过向 bean 指定一个或多个 schema 资源来执行 schema 验证,如下例所示:
<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
子元素提供要绑定到 marshaller 的类列表:
<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>
下表描述了可用的属性:
属性 | 描述 | 是否必须 |
---|---|---|
|
marshaller 的 ID |
否 |
|
JAXB Context path |
否 |
JiBX
JiBX 框架提供了一个类似于 Hibernate 为 ORM 提供解决方案:一个 binding definition 定义了 Java 对象如何转换为 XML 或从 XML 转换的规则。准备好 binding 并编译类后,JiBX binding compiler 会增强类文件并添加处理类实例与 XML 相互转换的代码。
有关 JiBX 的更多信息,请参阅JiBX 网站。Spring 集成类位于 org.springframework.oxm.jibx
包中。
使用 JibxMarshaller
JibxMarshaller
类同时实现了 Marshaller
和 Unmarshaller
接口。为了操作,它需要编组的类的名称,您可以使用 targetClass
属性进行设置。您可以选择通过设置 bindingName
属性来设置 binding 名称。在以下示例中,我们绑定了 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"/>
下表描述了可用的属性:
属性 | 描述 | 是否必须 |
---|---|---|
|
marshaller 的 ID |
否 |
|
此 marshaller 的目标类 |
是 |
|
此 marshaller 使用的 binding 名称 |
否 |
XStream
XStream 是一个简单的库,用于将对象序列化为 XML 并再反向转换。它不需要任何映射并生成干净的 XML。
有关 XStream 的更多信息,请参阅XStream 网站。Spring 集成类位于 org.springframework.oxm.xstream
包中。
使用 XStreamMarshaller
XStreamMarshaller
不需要任何配置,可以直接在应用上下文中配置。要进一步自定义 XML,您可以设置一个 alias 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>
默认情况下,XStream 允许任意类被解组,这可能导致不安全的 Java 序列化效应。因此,我们不建议使用 如果您选择使用
这样做可以确保只有已注册的类才有资格进行解组。 此外,您可以注册 custom converters 以确保只有您支持的类可以被解组。您可能希望将 |
请注意,XStream 是一个 XML 序列化库,而不是数据绑定库。因此,它的命名空间支持有限。结果,它不太适合在 Web Services 中使用。 |