《Spring官方文档1》17 使用 O/X(Object/XML)映射器对XML进行编组
17 使用 O/X(Object/XML)映射器对XML进行编组
17.1 简介
本章将讨论 Spring 对于 对象/XML 映射的支持。对象/XML 映射,或 O/X 映射,是指将 XML 文档与 XML 文档对象进行互相转换的操作。这一转换操作也被称作 XML 编组,或 XML 序列化。在本章中,这几个概念都指的是同一个东西。 在 O/X 映射中,将一组对象序列化为 XML 的操作是由一个编组器负责的。与之相对,一个反编组器则被用于将 XML 反序列化为一组对象。而这些操作中的 XML 文件来源可能是一份 DOM 文档,一个输入/输出流,或一个 SAX 管理器。 使用 Spring 提供的支持来实现你的 O/X 映射需求具有如下一些好处:
17.1.1 便于配置
Spring 的 bean 工厂使得无需构建 JAXB 上下文、JiBX 绑定工厂就可以配置编组器。你可以像配置你的应用中任何一个 Spring bean 一样地配置编组器。另外,相当一部分编组器可以使用基于 XML 架构(XML Schema-based)的配置来进行设置,这让配置工作变得更为容易。
17.1.2 一致的接口
Spring 的 O/X 映射通过两个全局的接口来执行操作:Marshaller 和 Unmarshaller。这一结构让用户可以在几乎不需要修改编组操作类的前提下,轻易地在不同的 O/X 映射框架之间进行切换。这一结构的另一优势是可以以一种非侵入的方式在代码中混合多种 XML 编组方法(比如有一些编组实现使用 JAXB,而另一些则使用 Castor),从而将各种技术的优势在应用中加以综合利用。
17.1.3 一致的异常继承
Spring 对来自底层 O/X 映射工具的异常进行了转换,以 XmlMappingException 的形式使之成为 Spring 自身异常继承体系的一部分。这些 Spring 运行时异常将初始异常封装其中,因此所有异常信息都会被完整地保留下来。
17.2 编组器与反编组器
就如在“简介”中提到的,一个编组器负责将一个对象序列化成 XML,而一个反编组器则将 XML 流反序列化为一个对象。我们将在本节对 Spring 提供的两个相关接口进行描述。
17.2.1 编组器
Spring 将所有编组操作抽象成了 org.springframework.oxm.Marshaller
中的方法,以下是该接口最主要的一个方法:
[code lang="java"] public interface Marshaller { /** * 将对象编组并存放在 Result 中. */ void marshal(Object graph, Result result) throws XmlMappingException, IOException; } [/code]
Marshaller
接口有一个主方法用于将一个给定对象编组为一个给定的 javax.xml.transform.Result
实现。这里的 Result
是一个用于代表某种 XML 输出格式的标记接口:不同的 Result
实现会封装不同的 XML 表现形式,详见下表:
Result 实现 |
封装的 XML 表达方式 |
DOMResult |
org.w3c.dom.Node |
SAXResult |
org.xml.sax.ContentHandler |
StreamResult |
java.io.File, java.io.OutputStream, or java.io.Writer |
尽管
marshal()
方法的第一个参数只是一个简单对象,但大多数Marshaller
实现并不真的能处理任意类型的对象。这个对象要么必须在映射文件中定义过映射关系,要么被注解所修饰,要么在编组器中进行过注册,要么与编组器实现拥有共同的基类。参考后面的章节来确定你所选用的 O/X 技术实现具体是怎么做的。
17.2.2 反编组器
与 Marshaller
接口相对应,还有一个 org.springframework.oxm.Unmarshaller
接口。
[code lang="java"] public interface Unmarshaller { /** * 将来源 XML 反编组成一个对象 */ Object unmarshal(Source source) throws XmlMappingException, IOException; } [/code]
此接口同样也有一个方法,从 javax.xml.transform.Source
(一个抽象的 XML 输入)读取 XML 数据,并返回一个相对应的 Java 对象。和 Result
接口一样,Source
是一个拥有三个具体实现的标记接口。每一个实现封装了一种 XML 表现形式。详见下表:
Source 实现 |
封装的 XML 表现形式 |
DOMSource |
org.w3c.dom.Node |
SAXSource |
org.xml.sax.InputSource, and org.xml.sax.XMLReader |
StreamSource |
java.io.File, java.io.InputStream, or java.io.Reader |
尽管有两个独立的接口(Marshaller
和 Unmarshaller
)分别代表编组器与反编组器,Spring 框架中所有对这两个接口的具体实现类都同时实现了这两个接口。这意味着你在 applicationContext.xml 中配置了编组器 bean 之后,可以把它们同时当做编组器与反编组器来使用。
17.2.3 XmlMappingException
Spring 对来自底层 O/X 映射工具的异常进行了转换,以 XmlMappingException
的形式使之成为 Spring 自身异常继承体系的一部分。 这些 Spring 运行时异常将初始异常封装其中,因此所有异常信息都会被完整地保留下来。 额外地,虽然底层的 O/X 映射工具并未提供支持,但 MarshallingFailureException
和 UnmarshallingFailureException
让编组与反编组操作中产生的异常得以能够被区分开来。 以下是 O/X 映射异常的继承层次:
17.3 Marshaller 与 Unmarshaller 的使用
Spring 的 OXM 可被用于十分广泛的场景。在以下的例子中,我们将使用这一功能将一个由 Spring 管理的应用程序的配置编组为一个 XML 文件。我们用了一个简单的 JavaBean 来表示这些配置:
[code lang="java"] public class Settings { private boolean fooEnabled; public boolean isFooEnabled() { return fooEnabled; } public void setFooEnabled(boolean fooEnabled) { this.fooEnabled = fooEnabled; } } [/code]
应用程序的主类使用这个 bean 来存放应用的配置信息。除了主要方法外,主类还包含下面两个方法:saveSettings()
将配置 bean 保存成一个名为 settings.xml
的文件, loadSettings()
则将配置信息从 XML 文件中读取出来。另有一个 main()
方法负责构建 Spring 应用上下文,并调用前述两个方法。
[code lang="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 FILENAME = "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 { FileOutputStream os = null; try { os = new FileOutputStream(FILENAME); this.marshaller.marshal(settings, new StreamResult(os)); } finally { if (os != null) { os.close(); } } } public void loadSettings() throws IOException { FileInputStream is = null; try { is = new FileInputStream(FILE_NAME); this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is)); } finally { if (is != null) { is.close(); } } } public static void main(String[] args) throws IOException { ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Application application = (Application) appContext.getBean("application"); application.saveSettings(); application.loadSettings(); } } [/code]
需要将 marshaller
和 unmarshaller
这两个属性赋值才能使 Application 正确运行。我们可以使用以下 applicationContext.xml
的内容来实现这一目的:
[code lang="xml"] <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> [/code]
该应用中使用了 Castor 这一编组器实例,但我们可以使用在本章稍后描述的任何一个编组器实例来替换 Castor。Castor 默认并不需要任何进一步的配置,所以 bean 定义十分简洁。另外由于 CastorMarshaller
同时实现了 Marshaller
与 Unmarshaller
接口,所以我们可以同时把 castorMarshaller
bean 赋值给应用的 marshaller
与 unmarshaller
属性。 此范例应用将会产生如下 settings.xml
文件:
[code lang="xml"] <?xml version="1.0" encoding="UTF-8"?> <settings foo-enabled="false"/> [/code]
17.4 基于 XML 架构的配置
可以使用来自 OXM 命名空间的 XML 标签使对编组器的配置变得更简洁。要使用这些标签,请在 XML 文件开头引用恰当的 XML 架构。以下是一个引用 oxm 的示例:
[code lang="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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"> [/code]
目前可用的标签有以下这些:
- jaxb2-marshaller
- jibx-marshaller
- castor-marshaller
接下来的章节中将逐一介绍每一个标签。下面先看一个 JAXB2 的配置示例:
[code lang="xml"] <oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/> [/code]
17.5 JAXB
JAXB 绑定编译器将 W3C XML 架构实现为一到数个 Java 类,一个 jaxb.properties
文件,可能还会有数个资源文件。JAXB 同时还支持从被注解的 Java 类生成 XML 架构。 Spring 支持基于 17.2 Marshaller 和 Unmarshaller 所提到的 Marshaller
和 Unmarshaller
结构实现的 JAXB 2.0 API 编组策略。相应的类文件都定义在 org.springframework.oxm.jaxb
包下面。
17.5.1 Jaxb2Marshaller
Jaxb2Marshaller
类同时实现了 Marshaller
和 Unmarshaller
接口。这个类需要通过 contextPath
配置好上下文路径才能正常运作。上下文路径是一组由冒号(:)分隔的 Java 包名。这些包下面包含了由 XML 架构所生成的对应 Java 类。另外你可以通过设置一个叫 classesToBeBound
的属性来配置一组可以被编组器支持的类。架构的验证则通过向 bean 中配置一到多个 XML 架构的 xsd 文件资源来实现。下面是一个 bean 的配置示例:
[code lang="xml"] <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> [/code]
基于 XML 架构的配置
jaxb2-marshaller
标签 配置了一个 org.springframework.oxm.jaxb.Jaxb2Marshaller
实例。以下是一个配置实例:
[code lang="xml"] <oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/> [/code]
如果要配置需要被绑定的类,则可以使用 class-to-be-bound
子标签:
[code lang="xml"] <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> [/code]
可用的标签属性如下表:
属性 |
描述 |
是否必需 |
id |
编组器的id |
no |
contextPath |
JAXB 上下文路径 |
no |
17.6
Castor XML 映射是一个开源的 XML 绑定框架。它允许使用者将包含在一个 Java 对象模型中的数据转换成 XML 文档,或者反之。Castor 默认并不需要额外的配置就可以使用。但如果使用者希望能够对框架行为拥有更多的控制,则可以通过在配置中引入一个映射文件来达到这一目的。 读者可以从 Castor 的项目主页上了解更多相关内容。Spring 对这一框架的集成代码都在 org.springframework.oxm.castor
包底下。
17.6.1 CastorMarshaller
与 JAXB 类似,CastorMarshaller
类同时实现了 Marshaller
和 Unmarshaller
接口。它可以通过以下配置来被引用:
[code lang="xml"] <beans> <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" /> ... </beans> [/code]
17.6.2 映射
尽管 Castor 的默认编组行为基本能够适应大部分应用场景,用户有时候还是需要一些自定义的能力。这一需求可以通过使用一个 Castor 的映射文件来实现。更多信息请参考 Castor XML Mapping。 映射文件可以通过 mapppingLocation
属性进行设置,如下是一个配置了 classpath 资源的示例:
[code lang="xml"] <beans> <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" > <property name="mappingLocation" value="classpath:mapping.xml" /> </bean> </beans> [/code]
基于 XML 架构的配置
一个 castor-marshaller
代表了一个 org.springframework.oxm.castor.CastorMarshaller
实例。示例如下:
[code lang="xml"] <oxm:castor-marshaller id="marshaller" mapping-location="classpath:org/springframework/oxm/castor/mapping.xml"/> [/code]
编组器实例可以用两种方式进行配置,一种是(通过 mapping-location
属性)指定映射文件的位置,另一种则是(通过target-class
或 target-package
属性)指定包含有相应 XML 描述信息的 Java POJO。后一种方式一般会与通过 XML 架构自动生成 Java 代码的功能结合使用。 以下是可用的标签属性:
属性 |
描述 |
是否必需 |
id |
编组器的id |
no |
encoding |
反编组 XML 文件使用的编码 |
no |
target-class |
一个 Java POJO 类名,此类中包含一个(由代码自动生成器生成的) XML 类的描述信息 |
no |
target-package |
一个包含了(由代码自动生成器生成的) POJO 和相应 Castor XML 描述类的 Java 包名 |
no |
mapping-location |
Castor XML 映射文件的位置 |
no |
17.7 JiBX
JiBX 框架提供的解决方案思路与 Hibernate 对于 ORM 的解决方案类似:通过一个绑定定义指定了你的 Java 对象与 XML 文件之间互相转换的规则。在准备好绑定并编译了类文件后,一个 JiBX 编译器将会对编译好的类文件进行增强,在其中加入一些辅助代码,并自动添加用于处理在类实例与 XML 文档之间相互转换的操作代码。 请参考 JiBX 官方网站来了解更多信息。Spring 对于框架的集成代码都在 org.springframework.oxm.jibx
包下面。
17.7.1 JibxMarshaller
JiBXMarshaller
类同时实现了 Marshaller
和 Unmarshaller
接口。它需要使用者设置编组的目标类的类名才能正确工作。设置类名的属性是 targetClass
。另外还有一个可选属性是 bindingName
,用户可以通过这个属性配置绑定名。接下来的示例中,我们将绑定 Flight
类:
[code lang="xml"] <beans> <bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller"> <property name="targetClass">org.springframework.oxm.jibx.Flights</property> </bean> ... </beans> [/code]
一个 JibxMarshaller
只能处理一个目标类与 XML 的相互转换,如果你需要编组多个类,你必需配置相应数量的 JibxMarshaller
bean,然后在 targetClass
里面指定相应各个类的类名。
基于 XML 架构的配置
jibx-marshaller
标签配置了 org.springframework.oxm.jibx.JibxMarshaller
的实例。以下是一个示例:
[code lang="xml"] <oxm:jibx-marshaller id="marshaller" target-class="org.springframework.ws.samples.airline.schema.Flight"/> [/code]
标签的可用属性如下:
属性 |
描述 |
是否必需 |
id |
编组器的id |
no |
target-class |
此编组器所对应的目标类 |
yes |
bindingName |
此编组器使用的绑定名 |
no |
17.8 XStream
XStream 是一个用于将对象与 XML 文档进行序列化与反序列化的简单类库。它不需要任何映射关系,并且会生成整齐的 XML 文档。 请参考 XStream 的项目主页以获取更多信息。Spring 对此框架的集成代码都在 org.springframework.oxm.xstream
包下面。
17.8.1 XStreamMarshaller
XStreamMarshaller
类不需进行任何配置便可直接在 applicationContext.xml
文件中直接配置成 bean 进行使用。不过你可以配置一个包含了字符串别名与类之间对应关系的 别名映射表 来实现对 XML 解析结果的自定义:
[code lang="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> [/code]
XStream 默认允许对任何类进行反编组操作,但这可能会导致安全隐患。因此不建议使用 XStreamMarshaller 对来源于外部(比如公网)的 XML 文档进行反编组。如果你坚持使用 XStreamMarshaller 反编组来自外部的 XML 文档,请如下例演示的一样设置 supportedClasses
属性:
[code lang="xml"] <bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"> <property name="supportedClasses" value="org.springframework.oxm.xstream.Flight"/> ... </bean> [/code]
设置这一属性能够确保只有指定的类才能够被用于反编组。
更进一步,你可以通过注册 自定义转换器 来确保只有你指定的类才能够被反编组。建议在明确指定了所有转换器后,在列表的最后加上
CatchAllConverter
,这样一来便可确保具有低优先级以及安全风险的 XStream 默认转换器不会被调用。
这里需要注意的是 XStream 是一个 XML 序列化类库,而非一个数据绑定类库,所以它对命名空间的支持有限, 这使得 XStream 并不适合于用在网络服务中。
原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 《Spring官方文档1》17 使用 O/X(Object/XML)映射器对XML进行编组
这这这是怎么回事,发布出来的格式怎么变得如此眼花缭乱