《Spring官方文件》17.利用O/X對映器編組XML
原文連結 譯者: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服務中使用。