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接口背后抽象了所有编组操作,其主要方法如下:
1
public interface Marshaller {
2
3
/**
4
* Marshal the object graph with the given root into the provided Result.
5
*/
6
void marshal(Object graph, Result result) throws XmlMappingException, IOException;
7
}
Copied!
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映射异常层次结构如下图所示:

使用Marshaller和Unmarshaller

您可以在多种情况下使用Spring的OXM。 在下面的示例中,我们使用它来将Spring托管应用程序的设置作为XML文件进行编组。 在下面的示例中,我们使用一个简单的JavaBean来表示设置:
1
public class Settings {
2
3
private boolean fooEnabled;
4
5
public boolean isFooEnabled() {
6
return fooEnabled;
7
}
8
9
public void setFooEnabled(boolean fooEnabled) {
10
this.fooEnabled = fooEnabled;
11
}
12
}
Copied!
应用程序类使用此bean存储其设置。 除了主要方法之外,该类还有两个方法:saveSettings()将settings Bean保存到名为settings.xml的文件中,loadSettings()再次加载这些设置。 下面的main()方法构造一个Spring应用程序上下文并调用这两个方法:
1
import java.io.FileInputStream;
2
import java.io.FileOutputStream;
3
import java.io.IOException;
4
import javax.xml.transform.stream.StreamResult;
5
import javax.xml.transform.stream.StreamSource;
6
import org.springframework.context.ApplicationContext;
7
import org.springframework.context.support.ClassPathXmlApplicationContext;
8
import org.springframework.oxm.Marshaller;
9
import org.springframework.oxm.Unmarshaller;
10
11
public class Application {
12
13
private static final String FILE_NAME = "settings.xml";
14
private Settings settings = new Settings();
15
private Marshaller marshaller;
16
private Unmarshaller unmarshaller;
17
18
public void setMarshaller(Marshaller marshaller) {
19
this.marshaller = marshaller;
20
}
21
22
public void setUnmarshaller(Unmarshaller unmarshaller) {
23
this.unmarshaller = unmarshaller;
24
}
25
26
public void saveSettings() throws IOException {
27
try (FileOutputStream os = new FileOutputStream(FILE_NAME)) {
28
this.marshaller.marshal(settings, new StreamResult(os));
29
}
30
}
31
32
public void loadSettings() throws IOException {
33
try (FileInputStream is = new FileInputStream(FILE_NAME)) {
34
this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
35
}
36
}
37
38
public static void main(String[] args) throws IOException {
39
ApplicationContext appContext =
40
new ClassPathXmlApplicationContext("applicationContext.xml");
41
Application application = (Application) appContext.getBean("application");
42
application.saveSettings();
43
application.loadSettings();
44
}
45
}
Copied!
该应用程序需要同时设置封送程序和取消封送程序属性。 我们可以使用以下applicationContext.xml来做到这一点:
1
<beans>
2
<bean id="application" class="Application">
3
<property name="marshaller" ref="castorMarshaller" />
4
<property name="unmarshaller" ref="castorMarshaller" />
5
</bean>
6
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
7
</beans>
Copied!
该应用程序上下文使用Castor,但是我们可以使用本章后面介绍的任何其他编组实例。 请注意,默认情况下,Castor不需要任何进一步的配置,因此Bean的定义非常简单。 还要注意,CastorMarshaller同时实现了Marshaller和Unmarshaller,因此我们可以在应用程序的marshaller和unmarshaller属性中引用castorMarshaller bean。
该示例应用程序生成以下settings.xml文件:
1
<?xml version="1.0" encoding="UTF-8"?>
2
<settings foo-enabled="false"/>
Copied!

5.4 XML配置命名空间

您可以使用OXM名称空间中的标签来更简洁地配置编组器。 要使这些标签可用,您必须首先在XML配置文件的序言中引用适当的架构。 以下示例显示了如何执行此操作:
1
<?xml version="1.0" encoding="UTF-8"?>
2
<beans xmlns="http://www.springframework.org/schema/beans"
3
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
xmlns:oxm="http://www.springframework.org/schema/oxm"
5
xsi:schemaLocation="http://www.springframework.org/schema/beans
6
https://www.springframework.org/schema/beans/spring-beans.xsd
7
http://www.springframework.org/schema/oxm https://www.springframework.org/schema/oxm/spring-oxm.xsd">
Copied!
当前,该模式使以下元素可用:
jaxb2-marshaller
jibx-marshaller
castor-marshaller
每个标签均在其各自的编组部分中进行了说明。 但是,作为示例,JAXB2编组器的配置可能类似于以下内容:
1
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>
Copied!

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指定一个或多个模式资源来执行模式验证,如以下示例所示:
1
<beans>
2
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
3
<property name="classesToBeBound">
4
<list>
5
<value>org.springframework.oxm.jaxb.Flight</value>
6
<value>org.springframework.oxm.jaxb.Flights</value>
7
</list>
8
</property>
9
<property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
10
</bean>
11
12
...
13
14
</beans>
Copied!
XML配置命名空间
jaxb2-marshaller元素配置org.springframework.oxm.jaxb.Jaxb2Marshaller,如以下示例所示:
1
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>
Copied!
或者,您可以使用要绑定的子类元素提供绑定到编组器的类的列表:
1
<oxm:jaxb2-marshaller id="marshaller">
2
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Airport"/>
3
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Flight"/>
4
...
5
</oxm:jaxb2-marshaller>
Copied!
下表描述了可用的属性:
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接口。 可以按以下方式进行连接:
1
<beans>
2
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
3
...
4
</beans>
Copied!

5.6.2 Mapping

尽管可以依赖Castor的默认编组行为,但可能需要对其进行更多控制。 您可以通过使用Castor映射文件来获得更多控制。 有关更多信息,请参见Castor XML映射。
您可以通过使用mappingLocation资源属性来设置映射,在以下示例中使用类路径资源来指示:
1
<beans>
2
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
3
<property name="mappingLocation" value="classpath:mapping.xml" />
4
</bean>
5
</beans>
Copied!
XML配置命名空间
castor-marshaller标记配置org.springframework.oxm.castor.CastorMarshaller,如以下示例所示:
1
<oxm:castor-marshaller id="marshaller" mapping-location="classpath:org/springframework/oxm/castor/mapping.xml"/>
Copied!
您可以通过两种方式配置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类:
1
<beans>
2
<bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
3
<property name="targetClass">org.springframework.oxm.jibx.Flights</property>
4
</bean>
5
...
6
</beans>
Copied!
JibxMarshaller为单个类配置。 如果要封送多个类,则必须使用不同的targetClass属性值配置多个JibxMarshaller实例。
XML配置命名空间
jibx-marshaller标记配置org.springframework.oxm.jibx.JibxMarshaller,如以下示例所示:
1
<oxm:jibx-marshaller id="marshaller" target-class="org.springframework.ws.samples.airline.schema.Flight"/>
Copied!

5.8 XStream

XStream是一个简单的库,用于将对象序列化为XML并再次返回。 它不需要任何映射并生成干净的XML。
有关XStream的更多信息,请参见XStream网站。 Spring集成类位于org.springframework.oxm.xstream包中。

5.8.1 使用XStreamMarshaller

XStreamMarshaller不需要任何配置,可以直接在应用程序上下文中进行配置。 要进一步自定义XML,可以设置一个别名映射,该映射由映射到类的字符串别名组成,如以下示例所示:
1
<beans>
2
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
3
<property name="aliases">
4
<props>
5
<prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
6
</props>
7
</property>
8
</bean>
9
...
10
</beans>
Copied!
默认情况下,XStream允许将任意类取消编组,这可能导致不安全的Java序列化效果。因此,我们不建议使用XStreamMarshaller从外部源(即Web)解组XML,因为这可能会导致安全漏洞。
如果选择使用XStreamMarshaller从外部源解组XML,请在XStreamMarshaller上设置supportedClasses属性,如以下示例所示:
1
<bean id = xstreamMarshaller” class = org.springframework.oxm.xstream.XStreamMarshaller”>
2
<property name = supportedClasses” value = org.springframework.oxm.xstream.Flight” />
3
...
4
</ bean>
Copied!
这样做可以确保只有注册的班级才有资格进行编组。
此外,您可以注册自定义转换器,以确保只能解组受支持的类。除了明确支持应支持的域类的转换器之外,您可能还想添加CatchAllConverter作为列表中的最后一个转换器。结果,不会调用具有较低优先级和可能的安全漏洞的默认XStream转换器。
最近更新 10d ago