IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services  >

Web 服务编程技巧和诀窍: 将 <xsd:any/> 元素用于自定义序列化

掌握 JAX-RPC 的序列化和反序列化

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Andre Tost (atost@us.ibm.com), 高级认证 IT 专家, IBM Software Group

2004 年 2 月 01 日

大多数情况下,JAX-RPC 假定出现在 SOAP 消息中的 XML 元素都应该映射到 Java 对象中去。对于简单类型和复杂类型如何映射各有其规则说明,JAX-RPC 实现通常都提供了生成处理映射所需代码的工具。好消息就是,如果您要处理应用程序中的 Java 对象,您不必担心数据的类型映射以及序列化和反序列化。也就是说,您不需要知道如何解析 XML 元素,如何将它交给适当的 Java 对象,反之亦然。然而,在某些情况下,您可能想掌握(反)序列化是如何实现的。或者您根本就不想将 XML 数据映射到 Java 对象中去。幸运的是,在 JAX-RPC 中就有办法能做到,本文将为您展示如何去做的技巧。

SOAP with Attachments API for Java(SAAJ)

JAX-RPC 规范依赖于 SAAJ 来处理 SOAP 消息的。SAAJ 定义了 SOAP 消息中各个部分的类与接口。首先介绍 javax.xml.soap.SOAPMessage 类,您可以通过这个类访问 javax.xml.soap.SOAPEnvelope 实例,紧接着又可以通过这个实例获取 javax.xml.soap.SOAPHeader 实例和 javax.xml.soap.SOAPBody 实例,等等。所有这些实例都是对 javax.xml.soap.SOAPElement 接口的扩展与继承,而这个接口本身也是对 W3C DOM Node 接口的扩展。

换句话说,SAAJ 给您提供了以 XML 为中心的角度来看待 SOAP 消息中的元素。JAX-RPC 将所有的消息处理都委托给了 SAAJ。请注意此处我并不打算全面地介绍 SAAJ,我只想讨论一些本文主题所需要的方面。





回页首


<xsd:any/> 元素

<xsd:any/> 元素是表示 XML 文档中任意 XML 内容的元素。顾名思义,它可以是任何一种 XML。这使您可以在 XML Schema 中创建复杂类型定义,而不用描述复杂类型的某些部分的具体结构。下面是一个示例(请参见 清单 1)展示了一个名为 Order 类型的定义。它包含两个普通元素和一个 <xsd:any/> 元素。

清单 1. 带有 <xsd:any/> 的 XML Schema
        
<schema elementFormDefault="qualified"
   targetNamespace="http://anytip.webservices.ibm.com"
   xmlns="http://www.w3.org/2001/XMLSchema">
   <complexType name="Order">
      <sequence>
         <element name="createDate" nillable="true" type="xsd:dateTime"/>
         <element name="customer" nillable="true" type="xsd:string"/>
         <xsd:any maxOccurs="unbounded"/>
      </sequence>
   </complexType>
</schema>

      

这种类型的实例可以包含任意多个附加 XML 元素同时却不违反 schema 定义。这样一来,您就可以将附加信息添加到 Order 元素,而不用在 Schema 中定义它的格式。





回页首


组合在一起

那么,JAX-RPC 如何处理包含 <xsd:any/> 元素的 XML Schema 呢?最新发布的 JAX-RPC 1.1规范中定义了这种元素被映射到 SAAJ 的 javax.xml.soap.SOAPElement 接口(请参阅 参考资料)。这意味着服务端点接口将会包含有一个参数或者在 schema 中用到 <xsd:any/> 的每个地方返回 javax.xml.soap.SOAPElement 类型的值,如果 maxOccurs 属性值大于1,就分别返回 javax.xml.soap.SOAPElement[] 类型的值。

因此,JAX-RPC 工具将从上面的样本 Schema 中生成以下类(请参见 清单 2)(与通常的情况一样,这个样本没有什么意义,仅仅只是说明了概念;如常,您也可以在 参考资料部分找到本文中的完整源代码):

清单 2. 生成的 Order 类
        
public class Order  implements java.io.Serializable {
    private java.util.Calendar createDate;
    private java.lang.String customer;
    private javax.xml.soap.SOAPElement[] _any;
    ...
}

      

所有这些与自定义序列化有什么关系呢?假定您的 Web 服务使用了一些您并不想映射到 Java 类中的数据,而是想让 JAX-RPC 引擎以 XML 形式将这些数据交给实现。该实现然后就就能够解析数据或者简单地将它作为 XML 传递到后端应用程序以进行进一步的处理。类似地,您可以创建一个客户端代理,这个代理允许您在 SOAPElement 而不是 Java 对象中传送。





回页首


示例

这个示例在您预先知道 XML 数据结构的情况下也能够正常运行。设想您使用的是一个 OrderManager Web 服务,它是基于某些搜索标准来返回 Order 数据的。每个 Order 实例都包含有很多行式项目(line items)。 清单 3 中是对 WSDL 的摘录。假定这是一个非常简单易懂的 Web 服务,我们将只关注此处的 <types> 部分。

清单 3. 用于 Web 服务的 WSDL
        
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions ...>
 <wsdl:types>
  <schema elementFormDefault="qualified" 
          targetNamespace="http://any.webservices.ibm.com" 
          xmlns="http://www.w3.org/2001/XMLSchema">
   <element name="getOrder">
    <complexType>
     <sequence>
      <element name="searchCriteria" 
               nillable="true" type="xsd:string"/>
     </sequence>
    </complexType>
   </element>
   <complexType name="Order">
    <sequence>
     <element name="createDate" nillable="true" type="xsd:dateTime"/>
     <element name="customer" nillable="true" type="xsd:string"/>
     <element name="lineItems" nillable="true" type="impl:LineItem"
              maxOccurs="unbounded"/>
    </sequence>
   </complexType>
   <complexType name="LineItem">
    <sequence>
     <element name="itemDesc" nillable="true" type="xsd:string"/>
     <element name="itemNumber" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
   <element name="getOrderResponse">
    <complexType>
     <sequence>
      <element name="getOrderReturn" 
               nillable="true" type="impl:Order"/>
     </sequence>
    </complexType>
   </element>
  </schema>
 </wsdl:types>
 ...
</definitions>

      

现在想象一下您不想让 JAX-RPC 引擎来生成与结构相映射的 LineItem Java 类(如 XML Schema 中所定义的),而想自己来处理 XML (或许因为您要将它直接作为 XML 存储在数据库中,以致于解析数据就显得毫无必要了)。因此,在此 Web 服务中生成客户端代码之前,您要更改 WSDL 文件,⒁? <xsd:any/> 元素替换掉表示 lineItem 的元素。这样现在的 Order 复杂类型看起来就跟您之前看到的完全一样了。JAX-RPC 工具现在将生成一个包含有 SOAPElement 属性的客户端 Order 类,而不是 lineItem 类。上面的示例已经展示该类。

现在,您可以创建将从 Web 服务检索 Order 的客户端代码,并以 XML 的格式使用行式项目信息。 清单 4 中是一个示例测试客户端,这个示例是使用 WebSphere Application Server V5.0.2 生成的,您可以看到它可以看起来是什么样的:

清单 4. 样本客户端代码
        
public class TestMain {
 public static void main(String[] args) throws Exception {
  OrderManager om = 
                  new OrderManagerServiceLocator().getOrderManager();
  Order order = om.getOrder("whatever");
  SOAPElement lineItem = order.get_any()[0];
  System.out.println("Line item is : "+lineItem.toString());
 }
}

      

此客户端应用程序将检索作为 Java 对象的 Order ,但行式项目信息是以 XML 的格式作为 SOAPElement 的一个数组返回的。





回页首


总结

JAX-RPC 提供了以 Java 为中心的角度来看待 Web 服务。如果您想自己处理 SOAP 消息中的某些 XML 结果,您可以使用 SAAJ API 并结合 <xsd:any/> 元素来实现。您可以期待着未来版本的 JAX-RPC 引擎实现将会使这一切更加容易。事实上,JAX-RPC 1.1 规范要求符合规范的工具对每种类型都提供是映射到 Java 类还是映射到 javax.xml.soap.SOAPElement 的选项。



参考资料



关于作者

Andre Tost 是 WebSphere Business Development 组的一位方案设计师,在那里他帮助 IBM 的策略联盟(IBM Strategic Alliance )合作伙伴使用 WebSphere 集成他们的应用程序。他主要研究整个 WebSphere 产品家族中的 Web 服务技术。在担任现在职务之前,他在各类开发和 IBM 软件开发中担任架构师角色已经有 10 年了,最近主要研究 WebSphere Business Components 产品。他来自德国,现在居住在 Rochester ,Minnesota,并在那里工作。在空闲时间,他喜欢与家人在一起或者有可能就看看足球。您可以通过 atost@us.ibm.com 与 Andre 联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款