使用IBM Rational Software Architect 在Java中處理XSD

myattitude發表於2009-05-26

引言

許多應用程式需要以一種或多種使用 XSD 指定的行業標準訊息格式表示資料。XSD 通常是指定行業標準訊息格式的理想方法,因為它跨平臺和程式語言受到廣泛支援(無論是本機支援還是通過庫支援)。但是,即使擁有此支援,由於特定於應用程式的資料結構與 XSD 之間的特性不匹配,將儲存在這些特定於應用程式的資料結構中的資料轉換為符合 XSD 的訊息(通常為 XML 訊息)會帶來挑戰。


圖 1. 在兩種特定於應用程式的資料結構之間提供公共訊息模型的行業標準 XSD(中心)
提供公共訊息模型的行業標準 XSD

在實現基於 Java 的 Web 服務時,這些特性不匹配會導致很難使用基於 Java API for XML-based RPC (JAX-RPC)、Java API for XML Web Services (JAX-WS) 或同時基於這兩者的工具包,自動化從特定於應用程式的資料結構到 XML 訊息的對映。

由於 XSD 與程式語言無關,它具有許多在 Java 物件中不直接受到支援的特性。此類特性的示例包括 xsd:choicexsd:group 資料型別以及 xsd:restriction 屬性。本文向您介紹如何建立消除這些資料型別的 Java 友好的 XSD。您將使用基於 XSL Transformation (XSLT) 的對映,從而將基於 Java 友好的(內部)XSD 的訊息轉換為全功能的(外部)XSD。對於本文中的特定示例,外部 XSD 為 Postsecondary Electronic Standards Council (PESC) 的 Common Record: CommonLine (CRC) 助學貸款訊息標準。

本文中用於建立與 CRC 1.4 XSD 相對應的 Java 友好的 XSD 的技術可應用於任何太複雜而在基於 Java 的 Web 服務工具包中不直接受支援的 XSD。首先讓我們看一下大致步驟:

  1. 使用 JAX-RPC 或 JAX-WS 為 XSD 介面生成服務實現(和測試客戶端)。
  2. 如果需要,則建立外部 XSD 的 Java 友好的簡化版本。
  3. 使用 Java 友好的 XSD 重新生成服務實現。
  4. 實現 JAX-RPC 或 JAX-WS 程式碼生成當前不支援的 XSD 約束。

系統要求

要按照本文所述進行操作,需要在系統上安裝以下軟體:

  • 帶 IBM WebSphere® Application Server Feature Pack for Web Services 的 IBM® Rational® Software Architect V7.0.0.6
  • IBM WebSphere Integration Developer V6.1

Feature Pack for Web Services 是 Rational Software Architect V7 的一個可選包,您可以使用 IBM Installation Manager 對其進行下載和安裝。安裝該功能包之後,確保通過在 Rational Software Architect 中單擊 Window > Preferences > General > Capabilities 啟用 Web Services Developer 功能。


匯入外部 XSD

您的第一個步驟是匯入外部 XSD 並基於該 XSD 建立 Web 服務描述語言(Web Services Description Language,WSDL)介面:

  1. 在 Rational Software Architect V7 中建立一個 Java 專案(例如,CRCLib)。
  2. PESC 網站匯入該 XSD。

    圖 2. 構成 CRC 標準的 XSD
    構成 CRC 標準的 XSD

  3. 通過右鍵單擊 CRCLib 專案並選擇 New > Other > WSDL 建立新的 WSDL 介面。
  4. 在 com.ibm.jxsd.services 目錄中建立名為 LoanProcessing.wsdl 的介面。
  5. 將操作名稱更改為 process,將輸入更改為 CommonRecordCommonlineReceipt,將輸出更改為 CommonRecordCommonlineResponse

    圖 3. 在 Rational Software Architect 中建立 WSDL 介面
    在 Rational Software Architect 中建立 WSDL 介面 

    建立 JAX-RPC 實現

    下一步,您將建立服務實現。實現技術的選擇將決定您對內部 XSD 所做的更改。給定基於 WebSphere Application Server 的部署環境,總共存在兩種技術選擇:JAX-RPC 和 JAX-WS。JAX-WS 是一種較新的規範,比 JAX-RPC 支援更多的 XSD 構造,因此不需要單獨的(內部)XSD。JAX-RPC 是一種較舊的規範,並且需要內部 XSD;但是由於它較舊,因此受到比 JAX-WS 更廣泛的支援和採用。

    CRC 標準
    本文的示例中使用的 XSD 來自於 Common Record:CommonLine 標準。Common Record:CommonLine (CRC) 標準同時描述了助學貸款流程中的參與者用於進行訊息交換的訊息和流程:學生、學校、借款人和擔保人。完整的 CRC 1.4 XSD 包括在七個檔案中,可以在 Web上的地址 http://www.pesc.org/interior.php?page_id=162 處找到。

    本文介紹 JAX-RPC 和 JAX-WS 實現所需要的更改,首先從 JAX-RPC 開始:

    1. 右鍵單擊 LoanProcessing.wsdl 檔案並選擇 Web Service > Generate Java bean Skeleton
    2. 使用 Generate Java bean Skeleton 嚮導,選擇一個新的專案名稱並確保 Web 服務執行時為 JAX-RPC
    3. 單擊 Finish 生成程式碼。您應該看到一個視窗開啟並顯示警告。讓我們檢查一下其中一些警告,並瞭解為什麼會發生這些警告。

    xsd:group

    無法在 Java 中通過 JAX-RPC 對映的 XSD 特性之一是 xsd:group 資料型別。它在 XSD 中的存在導致類似於清單 1 所示的 JAX-RPC 警告。


    清單 1. 由於 xsd:group 而產生的 JAX-RPC 警告
    WSWS3029W: Warning: The xml construct named 
    {urn:org:pesc:core:CoreMain:v1.4.0}OrganizationType cannot be 
    mapped to a java type.  The construct will be mapped to 
    javax.xml.soap.SOAPElement.
    

    由於 xsd:group 資料型別無法在 JAX-RPC 中進行明確的對映,因此一般將其對映到 Java 中的 SOAPElementSOAPElement 需要以程式設計方式對映到 xsd:group 才能正常工作(請參見清單 2 和 3)。


    清單 2. 包含 xsd:group 元素的 XSD
    
    ...
    
    
    
     
      
       ...
     
    
    


    清單 3. 為 xsd:group 元素生成的 JAX-RPC 程式碼
    ...
     private javax.xml.soap.SOAPElement[] organizationType; 
    ...
    

    替代方法

    以程式設計方式將生成的 SOAPElement 對映到 xsd:group 資料型別是一種脆弱的解決方案,並違反了儘可能避免直接修改所生成的程式碼的實踐。您不能更改來自於標準的 XSD,因此可以建立一個內部 XSD,在其中將 xsd:group 替換為 xsd:complexType,如清單 4 所示。


    清單 4. 在其中將 xsd:group 元素替換為 xsd:complexType 的 XSD
    
    ...
    
    
    
     
      
       ...
     
    
    

    雖然 xsd:groupxsd:complexType 都是容器資料型別,但它們並不完全相同。組封裝 allchoicesequence 元素,而 complexType 封裝屬性、巢狀元素和混合內容。因此您可能擔心在轉換到 xsd:complexType 時會失去 xsd:group 資料型別的某些表達功能。但是結果證明,xsd:choice 也不受 JAX-RPC 對映的支援,因此您無論如何都要在內部 XSD 中對此進行更改。xsd:sequencesxsd:complexType 中受支援(如清單 4 所示)。

    xsd:choice

    xsd:choice 是另一個不受 JAX-RPC 支援的 XSD 特性。針對 xsd:choice 的警告與清單 5 所示類似。


    清單 5. 由於 xsd:choice 而產生的 JAX-RPC 警告
    WSWS3029W: Warning: The xml construct named 
    {urn:org:pesc:core:CoreMain:v1.4.0}TestsType cannot be mapped to a 
    java type.  The construct will be mapped to 
    javax.xml.soap.SOAPElement.
    

    xsd:choice 資料型別描述了這樣一個結構,其中只有一個子元素可以是活動的或者可供選擇。Java 中不存在對應的結構,因此 JAX-RPC 同樣將 xsd:choice 資料型別對映到通用 SOAPElement(請參見清單 6 和 7)。


    清單 6. 包含 xsd:choice 元素的 XSD
    
     
      ...
       
        
        
        
       
      ...
     
    
    


    清單 7. 為 xsd:choice 元素生成的 JAX-RPC 程式碼
    ...
     private javax.xml.soap.SOAPElement[] testType; 
    ...
    

    替代方法

    要使您的 XSD 變得 Java 友好,您可以從出現 xsd:choice 的位置將其完全刪除,以便 JAX-RPC 能夠產生對映。沒有 xsd:choice 時,JAX-RPC 生成的程式碼將建立正確的類(請參見清單 8)。


    清單 8. 在其中將 xsd:group 元素替換為 xsd:complexType 的 XSD
    
    ...
    
    
    
     
      
       ...
     
    
    

    這可能讓人擔心 XSD 將允許訊息有多個元素,從而與外部 XSD 衝突。這種資料結構約束的弱化要求根據需要強化應用程式邏輯中的約束。但是,由於傳入資料來自於外部來源,並滿足外部 XSD,而傳出資料在傳輸前將根據外部 XSD 進行驗證,因此不存在應用程式接受或傳輸無效資料的危險。如果需要根據 XSD 約束對傳入資料或傳出資料進行權威驗證,可以考慮部署專用的網路邊緣裝置,例如 IBM WebSphere DataPower SOA Appliances 所提供的裝置。

    Russell Butek 的文章“Web 服務技巧: 將多型性作為 xsd:choice 的備選方法”描述了對 xsd:choice 的另一種替代選擇。

    將內部 XSD 對映到外部 XSD

    在完成從外部 XSD 到內部 XSD 的所有更改之後,您可以在 WebSphere Integration Developer V6.1 中建立一箇中介模組,此模組將在 IBM WebSphere Enterprise Service Bus 或在 IBM WebSphere Process Server 中執行。在該中介模組中,一個 XSLT 對映在內部和外部 XSD 之間轉換 XML 訊息(請參見圖 4)。

    建立中介流和 XSLT 對映超出了本文的範圍,但是WebSphere Integration Developer 幫助文件的構建中介流部分對此進行了詳細的描述。 此外,為了便於參考,下載部分作為專案交換檔案提供了為本文建立的中介模組。

    請參見圖 4 的大圖


    圖 4. 在 WebSphere Integration Developer 中將內部 XSD 對映到外部 XSD
    在 WebSphere Integration Developer 中將內部 XSD 對映到外部 XSD 

    建立 JAX-WS 實現

    在實際實現中,您將選擇一種實現技術:JAX-RPC 或 JAX-WS。但是出於完整性的考慮,下面介紹了在使用 JAX-WS 時需要對內部 XSD 做出的更改:

    1. 在 CRCLib 專案中,右鍵單擊 LoanProcessing.wsdl 檔案,然後選擇 Web Services > Generate Java bean skeleton

      圖 5. 在 WSDL 基礎上生成 Web 服務
      在 WSDL 基礎上生成 Web 服務

    2. 在視窗中,將 Web 服務執行時更改為 IBM WebSphere JAX-WS。如果 JAX-WS 選項未列出,這意味著未安裝 WebSphere Application Server Feature Pack for Web Services。

      圖 6. 用於生成 JAX-WS Web 服務的選項
      用於生成 JAX-WS Web 服務的選項

    3. 確保在視窗中選擇新的專案名稱(例如 LoanPWS),然後單擊 Next 以確保將 WSDL 複製到專案。
    4. 回到 Service Deployment Configuration 視窗,單擊 OK 生成所有程式碼。如果伺服器未執行,它將會啟動。

    生成的 Java

    程式碼成功生成而無任何錯誤或警告。成功地為整個 XSD 生成了對應的類,因此不需要任何單獨的內部 XSD。JAX-WS 實現將 xsd:group 資料型別(此資料型別沒有對應的 Java 表示形式)轉換為 xsd:complexType。這是您在為 JAX-RPC 實現的內部 XSD 中手動執行的相同轉換;但是在 JAX-WS 實現中,該轉換是隱式和自動的。

    xsd:choice

    JAX-WS 實現將 xsd:choice 資料型別表示為 Java 類的屬性,並且做出隱式和自動的轉換,同樣,此轉換與您使用內部 XSD 為 JAX-RPC 實現執行的轉換相同。

    確保僅設定其中一個選擇。例如,在清單 9 中,eSignatureCustodianType 中可以具有 LenderGuarantor 元素。


    清單 9. 包含 xsd:choice 元素的 XSD

    
     
      
       
        
         
         
        
       
      
      
       
        
         
         
        
       
      
     
    
    

    為此型別生成的 Java 程式碼如清單 10 所示。


    清單 10. 為 xsd:choice 元素生成的 JAX-WS 程式碼

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "eSignatureCustodianType", 
    namespace = "urn:org:pesc:core:CoreMain:v1.4.0", 
    propOrder = {
     "lender",
     "guarantor"
    })
    public class ESignatureCustodianType {
    
     @XmlElement(name = "Lender")
     protected ESignatureCustodianType.Lender lender;
     @XmlElement(name = "Guarantor")
     protected ESignatureCustodianType.Guarantor guarantor;
    

    請注意,LenderGuarantor 都存在 get 和 set 方法。您必須確保僅填充其中一個。

    不相容性

    XSD 資料型別可以描述在 Java 沒有等效表示式時的約束。因此,JAX-RPC 和 JAX-WS 都不能建立保留所有約束的對應 Java 類。讓我們看看 XSD 約束和 JAX-WS 中生成的對應 Java 程式碼的一些示例。

    長度約束

    在清單 11 中的 XSD 中,confirmationID 是一個最小長度為 1 和最大長度為 20 的字串。


    清單 11. 帶長度約束的 XSD

    
     
       Confirmation ID supplied 
      from the counseling session
     
     
      
      
     
    
    

    生成的 Java 程式碼如清單 12 所示。


    清單 12. 為帶長度約束的 XSD 生成的 Java 程式碼

    public class LoanCounselingType {
    
     @XmlElement(name = "ConfirmationID")
     protected String confirmationID;
     @XmlElement(name = "CompletionDate")
     protected XMLGregorianCalendar completionDate;
     @XmlElement(name = "CompletionTime")
     protected XMLGregorianCalendar completionTime;
    

    confirmationID 生成的 Java 程式碼只是一個不帶任何約束的 Java 字串。如果將該字串設定為無效長度的值,該程式碼沒有問題,但是生成的 XML 將無法通過驗證。為了避免這一點,您必須顯式地向程式碼新增字串長度檢查。

    必備約束

    另一個在 Java 中不受支援的 XSD 約束是必備 約束。例如,下面的 XSD 描述了一組必須從中選擇其一的列舉值(也就是說,值為 Null 或不做出選擇將是無效的)。


    清單 13. 帶必備約束的 XSD

    
     
      Code indicating the preferred or 
      actual method of delivering the promissory note to 
      the borrower
     
     
      
      
      
      
     
     
    

    生成的 JAX-WS 程式碼如清單 14 所示。


    清單 14. 為帶必備約束的 XSD 生成的 Java 程式碼

    public enum PromissoryNoteDeliveryCodeType {
     @XmlEnumValue("Paper")
     PAPER("Paper"),
     @XmlEnumValue("Email")
     EMAIL("Email"),
     @XmlEnumValue("Web")
     WEB("Web");
     private final String value;
    

    程式碼生成器正確地建立了 Java 列舉,但是不確保至少選擇其中一個值。因此,強制執行此約束同樣是您的責任。

    maxOccurs 約束

    您將在這裡檢查的最後一個不受支援的 XSD 約束是 maxOccurs。在該示例中(請參見清單 15)中,父元素 PellAwardResponseType 具有一個名為 FSACode 的子元素,此子元素應該出現零至三次。


    清單 15. 帶 maxOccurs 約束的 XSD

    
     
      
       
       
       
      
     
    
    

    生成的 Java 程式碼(請參見清單 16)將 FSACode 表示為字串列表。它沒有將該列表的長度限制為少於四個專案。


    清單 16. 為帶 maxOccurs 約束的 XSD 生成的 Java 程式碼

    public class PellAwardResponseType
     extends ResponseType
    {
     ….
     @XmlElement(name = "FSACode")
     protected List fsaCode;
    
    作者:Majeed Arni, 高階軟體工程師, IBM
    Anthony Young-Garner, 解決方案開發人員, IBM

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14780914/viewspace-604215/,如需轉載,請註明出處,否則將追究法律責任。

相關文章