Marshalling XML by Using Object-XML Mappers
Introduction
本章介绍 Spring 的对象 XML 映射支持。对象 XML 映射(简称 O-X 映射)是指 XML 文档对象之间的转换过程。这个转换过程也称为 XML 序列化或 XML 序列转换。本章将这些术语替换使用。
对于 O-X 映射领域,一个序列化器负责将一个对象(图形)序列化为 XML。类似地,一个解串器将 XML 解串为一个对象图形。这个 XML 可以作为 DOM 文档、输入或输出流,或一个 SAX 处理器。
在 O/X 映射中使用 Spring 的一些好处是:
Ease of configuration
Spring 的 bean 工厂很容易配置序列化器,而无需构建 JAXB 上下文、JiBX 绑定工厂等。你可以像在应用程序上下文中配置任何其他 bean 那样配置序列化器。此外,基于 XML 命名空间的配置可用于多个序列化器,使配置过程变得更简单。
Consistent Interfaces
Spring 的 O-X 映射通过两个全局接口进行操作:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/oxm/Marshaller.html[Marshaller
] 和 Unmarshaller
。这些抽象使你能够相对容易地切换 O-X 映射框架,几乎不需要对执行编组的类做任何更改。这种方法还有一个好处,就是可以混合匹配来进行 XML 编组(例如,使用 JAXB 执行部分编组,使用 XStream 执行其它部分编组),且不会产生干扰,让你可以使用每种技术的优势。
Marshaller
and Unmarshaller
如 introduction 所述,转换器将对象序列化为 XML,而解组器将 XML 流反序列化为对象。本节介绍用于此目的的两个 Spring 接口。
Understanding 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 | Wraps XML representation |
---|---|
|
|
|
|
|
|
尽管 |
Understanding 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 implementation | Wraps XML representation |
---|---|
|
|
|
|
|
|
尽管有两个单独的编排接口(Marshaller
和 Unmarshaller
),Spring-WS 中的所有实现都在一个类中实现了这两个接口。这意味着你可以接线到一个序列化器类,并在 applicationContext.xml
中将它同时用作序列化器和解串器。
Using Marshaller
and 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()
将 settings 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,但是我们也可以使用本章后面介绍的任何其他序列化器实例。请注意,默认情况下,XStream 不需要进一步配置,所以 bean 定义非常简单。另请注意,XStreamMarshaller
实现了 Marshaller
和 Unmarshaller
,因此我们可以在 marshaller
和 unmarshaller
的应用程序属性中引用 xstreamMarshaller
bean。
此样例应用会生成以下 settings.xml
文件:
<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>
XML Configuration Namespace
您可以使用 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" 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 | Reference the oxm schema. |
2 | 指定 oxm 模式位置。 |
该架构让以下元素可用:
每个标签在各自编组器的部分中进行了解释。然而,作为示例,JAXB2 编组器的配置可能类似于以下内容:
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>
JAXB
JAXB 绑定编译器将 W3C XML 架构转换为一个或多个 Java 类、一个 jaxb.properties
文件以及一些资源文件。JAXB 还提供一种从带注释的 Java 类中生成架构的方式。
Spring 支持 JAXB 2.0 API 作为 XML 编组策略,遵循 Marshaller
和 Unmarshaller
中描述的接口,分别为 xref:data-access/oxm.adoc#oxm-marshaller-unmarshaller[Marshaller
和 Unmarshaller
。相应的集成类位于 org.springframework.oxm.jaxb
包中。
Using Jaxb2Marshaller
Jaxb2Marshaller
类实现了 Spring 的 Marshaller
和 Unmarshaller
接口。它需要一个上下文路径才能运行。您可以通过设置 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 Configuration Namespace
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>
下表描述了可用的属性:
Attribute | Description | Required |
---|---|---|
|
编组器 ID |
No |
|
The JAXB Context path |
No |
JiBX
JiBX 框架提供了一个类似于 Hibernate 为 ORM 提供的解决方案:绑定定义定义了如何将您的 Java 对象转换为 XML 或从 XML 转换 Java 对象的规则。准备绑定并编译类之后,一个 JiBX 绑定编译器会增强类文件并将代码添加到从类实例或转换为 XML 的操作处理中。
有关 JiBX 的更多信息,请参阅 JiBX web
site。Spring 集成类位于 org.springframework.oxm.jibx
包中。
Using JibxMarshaller
JibxMarshaller
类实现了 Marshaller
和 Unmarshaller
接口。要运行,它需要要编组成的类的名称,您可以使用 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 Configuration Namespace
jibx-marshaller
标记会配置一个 org.springframework.oxm.jibx.JibxMarshaller
,如下例所示:
<oxm:jibx-marshaller id="marshaller" target-class="org.springframework.ws.samples.airline.schema.Flight"/>
下表描述了可用的属性:
Attribute | Description | Required |
---|---|---|
|
编组器 ID |
No |
|
此编组器的目标类 |
Yes |
|
此编组器使用的绑定名称 |
No |
XStream
XStream 是一用于将对象序列化成 XML 并再次返回对象的简单库。它不需要任何映射并会生成简洁的 XML。
有关 XStream 的更多信息,请参阅 XStream
web site。Spring 集成类位于 org.springframework.oxm.xstream
包中。
Using 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
从外部来源取消编组 XML(即 Web),因为这可能导致安全漏洞。
如果你选择使用 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 服务中使用。 |