使用对象-XML 映射器编组 XML

引言

本章描述了Spring的对象-XML映射支持。对象-XML映射(简称O-X映射)是将XML文档转换为对象,以及将对象转换为XML文档的过程。这种转换过程也称为XML调度(XML Marshalling)或XML序列化(XML Serialization)。本章交替使用这些术语。

在O-X映射领域中,调度器(marshaller)负责将对象(图)序列化为XML。类似地,解调度器(unmarshaller)将XML反序列化为对象图。此XML可以采用DOM文档、输入或输出流或SAX处理器的形式。

使用Spring进行O/X映射的一些好处包括:

易于配置

Spring的bean工厂使得配置调度器变得容易,而无需构建JAXB上下文、JiBX绑定工厂等。您可以像配置应用程序上下文中任何其他bean一样配置调度器。此外,对于许多调度器,可以使用基于XML命名空间的配置,使配置更加简单。

一致的接口

Spring的O-X映射通过两个全局接口操作:MarshallerUnmarshaller。这些抽象使您可以相对轻松地切换O-X映射框架,而对执行调度操作的类几乎不需要或根本不需要更改。这种方法还有一个额外的好处,使得以非侵入式方式进行XML调度(例如,一些调度使用JAXB完成,另一些使用XStream完成)成为可能,让您充分利用每种技术的优势。

一致的异常层次结构

Spring提供了一个转换,将底层O-X映射工具的异常转换为其自己的异常层次结构,其中XmlMappingException是根异常。这些运行时异常包装了原始异常,因此不会丢失任何信息。

MarshallerUnmarshaller

引言所述,调度器将对象序列化为XML,解调度器将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。结果是一个标记接口,它基本上代表了一个XML输出抽象。具体的实现包装了各种XML表示形式,如下表所示:

Result 实现 包装的XML表示

DOMResult

org.w3c.dom.Node

SAXResult

org.xml.sax.ContentHandler

StreamResult

java.io.Filejava.io.OutputStreamjava.io.Writer

尽管marshal()方法接受一个普通对象作为其第一个参数,但大多数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表示

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将底层O-X映射工具的异常转换为自己的异常层次结构,其中XmlMappingException作为根异常。这些运行时异常包装了原始异常,因此不会丢失任何信息。

此外,MarshallingFailureExceptionUnmarshallingFailureException在调度和解调度操作之间提供了区分,即使底层O-X映射工具没有这样做。

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

oxm exceptions

使用 MarshallerUnmarshaller

您可以在各种情况下使用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来存储其设置。除了一个主方法外,该类还有两个方法: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需要设置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配置文件的前言中引用相应的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提供以下元素:

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

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

JAXB

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

Spring支持JAXB 2.0 API作为XML调度策略,遵循MarshallerUnmarshaller中描述的MarshallerUnmarshaller接口。相应的集成类位于org.springframework.oxm.jaxb包中。

使用 Jaxb2Marshaller

Jaxb2Marshaller 类实现了Spring的MarshallerUnmarshaller接口。它需要一个上下文路径才能运行。您可以通过设置contextPath属性来设置上下文路径。上下文路径是一个由冒号分隔的Java包名列表,这些包名包含由schema派生出来的类。它还提供了一个classesToBeBound属性,允许您设置一个由调度器支持的类数组。通过为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子元素向调度器提供要绑定的类列表:

<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之间的转换。

有关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服务中使用。
© . This site is unofficial and not affiliated with VMware.