原文链接 译者:kdmhh
17. 利用O/X映射器编组XML
17.1 引言
这一章,我们将介绍Spring对对象/XML映射器的支持。对象/XML映射器或者简称O/X映射器,是一种在XML文档和对象之间互相转换的行为。这种转换过程也叫做XML编组或者XML序列化。本章将交替使用这两种术语。
在O/X映射器中,编组是指把对象序列化为XML的过程。同样,解组是指XML反序列化为对象,XML可以是DOM文档、输入输出流或者SAX处理程序。
使用Spring处理O/X映射器的好处是:
17.1.1 简化的配置
Spring的bean工厂使得不需要构建JAXB、JiBX等第三方工具,就可以轻松配置编组器。编组器在应用程序上下文中可以配置为任意的bean。另外,基于XML的配置可应用于不同的编组器,并让配置更加简单化。
17.1.2 统一的接口
Spring的O/X映射器通过两个全局接口来实现:Marshaller 和 Unmarshaller。这些接口使你可以相对轻松切换O/X映射框架,你只需改动少量或者无需改动实现编组器的类。这种方式的另外优点是在同一个应用程序中以一种非侵入式的方式,将多种技术通过混合的方式来实现编组(比如,一些编组通过JAXB实现,而另外的通过Castor)。
17.1.3 统一的异常层次结构
Spring提供了基于底层O/X映射工具自身的异常层次结构,以XmlMappingException作为基础异常。这样原始异常被包装到Spring运行时异常中,保证了没有信息丢失。
17.2 编组和解组
正如引言中所述,编组是将对象序列化为XML,解组是将XML流反序列化为对象。这一章节,我们讲描述达到此目标的两个Spring接口。
17.2.1 编组
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表示 |
---|---|
DOMResult | org.w3c.dom.Node |
SAXResult | org.xml.sax.ContentHandler |
StreamResult | java.io.File, java.io.OutputStream, 或者 java.io.Writer |
尽管marshal()方法接收一个普通对象作为它的第一个参数,但大多数编组器实现不能处理任意对象。相反地,对象类必须映射到文件中,标记为注释,并且注册为编组器,或者有一个公共基类。请参阅本章节的其他内容,来决定你的O/X技术选择。
17.2.2 解组
与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.InputSource 和 org.xml.sax.XMLReader |
StreamSource | java.io.File,java.io.InputStream 或者java.io.Reader |
尽管有两个单独的编组接口(Marshaller 和 Unmarshaller),但是所有在Spring-WS中的实现都在同一个类中。这意味着你也可以在applicationContext.xml引用同一个编组器类,并将其同时作为编组器和接编器。
17.2.3 XmlMappingException
Spring提供了基于底层O/X映射工具自身的异常层次结构,以XmlMappingException作为基础异常。这样原始异常被包装到Spring运行时异常中,保证了没有信息丢失。
另外,尽管基于底层O/X的映射工具并未提供,但是,MarshallingFailureException 和 UnmarshallingFailureException提供了编组和解组之间的差异操作。
O/X映射异常层次结构如下所示:
17.3 使用编组器和解组器
Spring的OXM可以被使用在各种场景下,在下面的实例中,我们将使用它把Spring管理的应用设置编组为XML文件,我们使用一个简单的JavaBean来表示这种设置。
public class Settings {
private boolean fooEnabled;
public boolean isFooEnabled() {
return fooEnabled;
}
public void setFooEnabled(boolean fooEnabled) {
this.fooEnabled = fooEnabled;
}
}
Application类使用这个类存储配置信息,除了main方法,这个类有两个方法:saveSettings()方法用来保存配置bean到settings.xml文件,loadSettings()方法用来再次加载这些配置。main()方法构造了Spring应用上下文,并调用了这两个方法。
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 {
FileOutputStream os = null;
try {
os = new FileOutputStream(FILE_NAME);
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();
}
}
Application 同时需要设置marshaller 和 unmarshaller两个属性,我们通过下面的applicationContext.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>
这个应用上下文使用了Castor,但是你可以使用任一在本章节中介绍的其他编组器接口。注意的是,Castor在默认情况下不需要任何进一步的配置,所以bean的定义相当简单。同样需要注意的是,CastorMarshaller同时实现了Marshaller 和 Unmarshaller,所以我们可以同时在marshaller 和 unmarshaller 两个属性中引用castorMarshaller bean。
这个样例应用生成以下settings.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>
17.4 XML配置
可以使用OXM命名空间标记更加简洁地配置编组器。要使这些标签可用,必须首先在XML配置文件头部引入适当的模板,注意下面“OXM”相关的配置:
<?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">
目前,可以使用以下标签:
每个标记将在各自的编组器部分中进行详述。这里据一个示例,下面是JAXB2编组器的配置方式:
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>
17.5 JAXB
JAXB绑定编辑器将一个W3C XML模板转换为一个或多个java类,jaxb.properties配置文件或者其他资源文件。JAXB还提供了从注解类生成模板的方法。
17.5.1 Jaxb2Marshaller
Jaxb2Marshaller类同时实现了Spring的Marshaller和Unmarshaller接口,它需要上下文路径,你可以通过contextPath属性设置。上下文路径是一个以冒号分割的java包名列表,这些包包含从模板派生的类。它还提供了一个classestobe绑定属性,允许你设置为类的数组,这些类要被编组器所支持。通过向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的配置
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上下文路径 | 否 |
17.6 Castor
Castor XML映射是一个开源的XML绑定框架,它允许在java对象包含的数据和XML文档之间互相转换。默认情况下,它不需要任何进一步的配置,但是可以通过映射文件对Castor的行为进行更多的控制。
关于Castor更多的信息,请参阅Castor站点。Spring集成Castor的类放在org.springframework.oxm.castor包下。
17.6.1 CastorMarshaller
与JAXB类似,CastorMarshaller也同时实现了Marshaller 和Unmarshaller 接口,它可以通过如下方式配置:
<beans>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
...
</beans>
17.6.2 映射器
尽管可以依赖Castor的默认编组行为,但是可能需要对它进行更多的控制,可以使用Castor映射文件来进行控制,更多的信息,请参考Castor XML映射。
映射器可以通过mappingLocation属性来设置,可以通过如下的classpath资源来表示:
<beans>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
<property name="mappingLocation" value="classpath:mapping.xml" />
</bean>
</beans>
XML配置
通过castor-marshaller标签配置org.springframework.oxm.castor.CastorMarshaller,下面是示例:
<oxm:castor-marshaller id="marshaller" mapping-location="classpath:org/springframework/oxm/castor/mapping.xml"/>
编组器实例可以通过两种方式配置,一种是指定映射文件的地址(通过mapping-location属性),另一种是通过识别java POJOs(通过target-class或target-package属性)对应的XML描述类。第二种方法通常与XML模板生成的XML代码结合使用。
可用的属性如下:
属性 | 描述 | 是否必需 |
---|---|---|
id | 编组器的id | 否 |
encoding | XML解码的编码格式 | 否 |
target-class | Java类名,一个可以使用XML类描述符的POJO(通过代码生成) | 否 |
target-package | java包名,标识包含POJO及其相应的Castor XML描述类的包 | 否 |
mapping-location | Castor XML映射文件的路径 | 否 |
17.7 JiBX
JiBX框架提供了与Hibernate提供的ORM类似的解决方案:定义了Java对象和XML相互转换的规则。在准备好绑定和编译类之后,JiBX绑定编译器会增强类文件,并添加代码来处理类和XML相互转化的实例。
更多的信息,请参考JiBX web site,Spring集成JiBX的类放在org.springframework.oxm.jibx包下。
17.7.1 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配置
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 | 编组器使用的绑定名称 | 否 |
17.8 XStream
XStream是一个简单类库,用于在对象和XML之间转换。它不需要任何映射器就可以生成XML。
更多信息,请参阅XStream web,Spring集成XStream的类在org.springframework.oxm.xstream包下。
17.8.1 XStreamMarshaller
XStreamMarshaller不需要任何配置,可以直接在上下文中配置。可以通过设置analiasMap属性进一步设置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允许任意类被解组,这可能导致安全漏洞。因此,不建议使用XStreamMarshaller从外部资源(即Web资源)中对XML进行解组,因为这会导致安全漏洞。如果确实使用了XStreamMarshaller从外部资源解组,那需要在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服务中使用。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/99869.html