通过对象-XML映射器进行XML编组
介绍
本章介绍了Spring的对象-XML映射支持。对象-XML映射(简称O-X映射)是将XML文档转换为对象的过程。这个转换过程也被称为XML编组,或者XML序列化。本章中这些术语可以互换使用。
在O-X映射领域中,编组器负责将对象(图)序列化为XML。类似地,解组器将XML反序列化为对象图。这个XML可以采用DOM文档、输入或输出流或SAX处理程序的形式。
使用Spring进行O/X映射的一些好处包括:
配置简便
Spring的bean工厂使得配置编组器变得简单,无需构建JAXB上下文、JiBX绑定工厂等。您可以像配置应用程序上下文中的任何其他bean一样配置编组器。此外,基于XML命名空间的配置适用于许多编组器,使得配置更加简单。
一致的接口
Spring的O-X映射通过两个全局接口操作:Marshaller
和 Unmarshaller
。这些抽象让您可以相对轻松地切换O-X映射框架,几乎不需要对执行编组操作的类进行任何更改。这种方法的额外好处是可以以非侵入性的方式进行混合和匹配的XML编组(例如,一些使用JAXB执行编组,一些使用XStream),让您可以利用每种技术的优势。
Marshaller
和 Unmarshaller
如在介绍中所述,编组器将对象序列化为XML,解组器将XML流反序列化为对象。本节描述了用于此目的的两个Spring接口。
理解 Marshaller
Spring将所有编组操作抽象在org.springframework.oxm.Marshaller
接口背后,其主要方法如下:
public interface Marshaller {
/**
* 使用给定的根对象图对提供的结果进行编组。
*/
void marshal(Object graph, Result result) throws XmlMappingException, IOException;
}
Marshaller
接口有一个主要方法,将给定的对象编组为给定的javax.xml.transform.Result
。结果是一个标记接口,基本上表示XML输出抽象。具体实现包装了各种XML表示,如下表所示:
结果实现 | 包装的XML表示 |
---|---|
|
|
|
|
|
|
尽管marshal() 方法接受一个普通对象作为其第一个参数,但大多数Marshaller 实现无法处理任意对象。相反,对象类必须在映射文件中映射,用注解标记,注册到编组器中,或者具有一个公共基类。请参考本章后面的部分,以确定您的O-X技术如何管理这一点。 |
理解 Unmarshaller
类似于Marshaller
,我们有org.springframework.oxm.Unmarshaller
接口,如下列表所示:
public interface Unmarshaller {
/**
* 将提供的源解组为对象图。
*/
Object unmarshal(Source source) throws XmlMappingException, IOException;
}
这个接口也有一个方法,从给定的javax.xml.transform.Source
(一个XML输入抽象)读取并返回读取的对象。与Result
一样,Source
是一个标记接口,有三个具体实现。每个包装了不同的XML表示,如下表所示:
源实现 | 包装的XML表示 |
---|---|
|
|
|
|
|
|
尽管有两个单独的编组接口(Marshaller
和Unmarshaller
),Spring-WS中的所有实现都在一个类中同时实现了这两个接口。这意味着您可以将一个编组器类连接起来,并在您的applicationContext.xml
中既将其作为编组器,又将其作为解组器引用。
使用 Marshaller
和 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
}
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
需要设置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>
XStreamMarshaller
同时实现了
Marshaller
和
Unmarshaller
,因此我们可以在应用程序的
marshaller
和
unmarshaller
属性中引用
xstreamMarshaller
bean。
settings.xml
文件:
<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>
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 | 引用oxm 模式。 |
2 | 指定oxm 模式位置。 |
<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
接口中描述的接口。相应的集成类位于org.springframework.oxm.jaxb
包中。
使用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配置命名空间
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 |
否 |
|
JAXB上下文路径 |
否 |
JiBX
JiBX框架提供了一种类似于Hibernate为ORM提供的解决方案:绑定定义定义了Java对象如何转换为XML或从XML转换的规则。在准备绑定并编译类之后,JiBX绑定编译器增强类文件并添加处理将类的实例从XML转换为XML的代码。
有关JiBX的更多信息,请参阅JiBX网站。Spring集成类位于org.springframework.oxm.jibx
包中。
使用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
实例。
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序列化效果。因此,我们不建议使用 如果选择使用
这样可以确保只有注册的类有资格进行反序列化。 此外,您可以注册自定义转换器,以确保只有您支持的类可以进行反序列化。您可能希望在列表中添加一个 |
请注意,XStream是一个XML序列化库,而不是数据绑定库。因此,它对命名空间的支持有限。因此,它在Web服务中的使用相对不太适合。 |