改善J2EE与.NET之间的互操作性(二)

 
   | |

导读:Web服务操作的输入参数及数据类型的返回值对于Web服务的互操作性产生影响。Web服务用作XML文档转换的传送器。当数据对象被放入Web服务时,被序列化成XML数据表示。

关键词:Web服务 数据类型 互操作性 XML XML数据

 
正在加载数据...

  该系列文章中的第2部分探索对于公共的互操作性的需求来源,该需求面向跨平台的Web服务集成。跟随Wangming Ye分析互操作的失败原因——使用某些数据类型,以及克服错误的方法(如使用集合、数组或原始数据类型)。

  引言

  该系列文章的第I部分讨论了在编码之前设计Web服务描述语言(Web Services Description Language,WSDL)和XML Schema数据类型(XML Schema data types,XSD)的重要性,完全转换成文档或文字式样的基本原理,以及当开发Web服务的时候测试WS-I Basic Profile一致性的必要性。本文阐明了数据类型的用法及其对互操作性产生的影响。

  Web服务操作的输入参数及数据类型的返回值对于Web服务的互操作性产生非常大的影响。Web服务用作XML文档转换的传送器。当数据对象被放入Web服务栈中时,它们被序列化成XML数据表示。另一方面,Web服务栈需要准确地知道如何将那些XML数据表示映射到本地应用程序环境的需求中(例如XML数据的反序列化)。XML Schema定义驱动了映射。XSD的目的是确保发送的类型在其他终端有可复写的版本。但是由于基本技术(企业版Java 2平台(Java 2 Platform,Enterprise Edition,J2EE)与Mircosoft .NET)的实现是不同的,所以XSD和那些平台上的本地数据类型之间的映射可能会不同。某些差异可能导致反序列化的失败,而其它的可能导致信息失真。

  在接下来的部分中,我将讨论一些有关数据类型的互操作性的问题,例如:

  ·提供商用于精确解释XML Schema的工具是不存在的,XML Schema代表弱类型的集合对象并将它们映射成正确的本地数据类型。
  ·含有空元素的数组的XML表示不同于.NET和IBM WebSphere。
  ·由于缺乏本地和XSD数据类型所共享的一对一的映射,所以转译问题导致了信息的丢失或精度的降低。

  在Web服务方法签名中的复合数据类型集

  集合对象可能包括任何数据类型的元素。因此,许多人把它们看作弱类型的数据结构。这使得它们成为非常好的编程工具。在面向对象的编程中,有大量的集合类型库。例如,在Java中存在:

  ·java.util.Hashtable
  ·Vectors
  ·Hashmap
  ·Set
  ·ArrayList

  而在C#中存在:

  ·System.Collections.Hashtable
  ·SortedList
  ·Queue
  ·Stack
  ·ArrayList

  如果在整个Web服务中公布了这些集合类型,那么它们可能引发不能被解决的问题。该问题是接收方如何能理解被序列化了的简单对象访问协议(Simple Object Access Protocol,SOAP)消息,这些消息中包含弱类型对象元素及本地数据类型。

  即使一些集合类型看上去与某些语言非常相似,例如C#中的System.Collections.ArrayList及Java中的java.util.ArrayList,记住集合中的元素是通用的参照。为了准确地解组集合的XML表示,客户必须预先了解原始的具体类型。这个任务交给工具包开发人员来解释Web服务提供者所发布的XML Schemas并将SOAP消息映射到本地数据中——不是对于弱类型集合的简单任务。

  现在,让我们来看一看Collection类型的XML Schemas是什么样子。这次,考虑部署在Microsoft .NET框架上的Web服务。假设InventoryService接受Product的System.Collections.ArrayList作为变量,为ArrayList中的每个产品设置新价格(增长了百分之10),并且返回System.Collections.ArrayList类型的新对象。

  清单1. 在C#中Web服务的详细目录
  namespace Inventory
  {
    [WebService(Namespace="http://services.inventory")]
    public class InventoryService: WebService
    {
   //increase the product price by 10 percent
 private static float inc_rate = 0.10F;
 public struct Product {
  public string name;
  public int  qty;
  public float price;
 }
 [WebMethod]
 [XmlInclude(typeof(Product))]
 public ArrayList updateProductPrice(ArrayList products)
 {
  ArrayList newList = new ArrayList();
  IEnumerator eList = products.GetEnumerator();
  while(eList.MoveNext())
  {
     Product item = (Product)(eList.Current);
     item.price = item.price * (1 + inc_rate);
     newList.Add(item);
  }
  return newList;
   }
     }
  }
 
  在.NET框架中的WSDL引擎生成了用于Collection类型、ArrayList以及Product复合类型的如下的XML Schema:

  清单2. 用于ArrayList和Product的XML Schema

  1. <types>
  2. <s:schema xmlns:s="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://services.inventory">
  3. <s:element name="updateProductPrice">
  4. <s:complexType>
  5. <s:sequence>
<s:element maxOccurs="1" minOccurs="0" name="products"
type="s0:ArrayOfAnyType"/>
  6. </s:sequence>
  7. </s:complexType>
  8. </s:element>
  9. <s:complexType name="ArrayOfAnyType">
  10. <s:sequence>
  11. <s:element maxOccurs="unbounded" minOccurs="0" name="anyType"
nillable="true"/>
  12. </s:sequence>
  13. </s:complexType>
  14. <s:complexType name="Product">
  15. <s:sequence>
  16. <s:element maxOccurs="1" minOccurs="0" name="name" type="s:string"/>
  17. <s:element maxOccurs="1" minOccurs="1" name="qty" type="s:int"/>
  18. <s:element maxOccurs="1" minOccurs="1" name="price" type="s:float"/>
  19. </s:sequence>
  20. </s:complexType>
  21. <s:element name="updateProductPriceResponse">
  22. <s:complexType>
  23. <s:sequence>
<s:element maxOccurs="1" minOccurs="0" name="updateProductPriceResult"
type="s0:ArrayOfAnyType"/>
  24. </s:sequence>
  25. </s:complexType>
  26. </s:element>
  27. </s:schema>
  28. </types>
 
  从第9行到第13行(详见清单2)定义了复合类型xsd:ArrayOfAnyType,连同anyType元素的无界序列。Products的ArrayList已经被翻译成了XML Schema定义中的匿名元素序列。这是所期望的;但是,它也引发了两个问题。首先,其它的Collection类型也将被翻译成xsd:ArrayOfAnyType。因此,在另一个平台上的SOAP工具包如何确定将它映射成哪种Collection类型?

  其次,当没有指定类型的时候xsd:anyType就是缺省的类型。清单2中的第11行是需要的,因为Collection中的对象是通用的参照——在运行之前并不知道类型。当在另一个平台上的SOAP工具包接收到序列化的对象时问题发生了。您如何找出正确的序列化器来将XML载荷反序列化到具体的对象中?

  事实上,JAX-RPC从清单2的xsd:ArrayOfAnyType schema中生成了如下的帮助类。

  清单3. 用于xsd:ArrayOfAnyType schema的作为结果的帮助类
  public class ArrayOfAnyType  implements java.io.Serializable {
      private java.lang.Object[] anyType;
   <!-- The setter, getter, equals() and hashCode() methods -->
  }
 
  从清单3中,您可以看到xsd:ArrayOfAnyType schema的不明确性已经导致JAX-RPC工具生成了帮助类。该帮助类将通用的java.lang.Object[]数组作为它的私有字段,取代了具体的Product数组。

  为了消除这种不明确性,您可以使用ArrayOfRealType来代替xsd:ArrayOfAnyType。您应当仅公布具体类型的简单数组(也就是Product[]),将其作为Web服务方法的签名。

  对于清单1中的Web服务,公布前端方法:

  清单4. 公布简单数组Product[]的前端方法
   [WebMethod]
 [XmlInclude(typeof(Product))]
 public Product[] updateProductPriceFacade(Product[] products)
 {
  ArrayList alist = new ArrayList();
  IEnumerator it = products.GetEnumerator();
  while (it.MoveNext())
   alist.Add((Product)(it.Current));
  alist = updateProductPrice(alist);
  Product[] outArray = (Product[])alist.ToArray(typeof(Product));
  return outArray;
 }
 
  对于输入输出消息部分的新schemas是:

  清单5. 对于清单4中的新的Web服务的XML Schema

  1. <s:element name="updateProductPriceFacade">
  2. <s:complexType>
  3. <s:sequence>
  4. <s:element minOccurs="0" maxOccurs="1" name="products"
type="s0:ArrayOfProduct" />
  5. </s:sequence>
  6. </s:complexType>
  7. </s:element>
  8. <s:complexType name="ArrayOfProduct">
  9. <s:sequence>
  10. <s:element minOccurs="0" maxOccurs="unbounded" name="Product"
type="s0:Product" />
  11. </s:sequence>
  12. </s:complexType>
  13. <s:element name="updateProductPriceFacadeResponse">
  14. <s:complexType>
  15. <s:sequence>
  16. <s:element minOccurs="0" maxOccurs="1"
name="updateProductPriceFacadeResult" type="s0:ArrayOfProduct" />
  17. </s:sequence>
  18. </s:complexType>
  19. </s:element>
 
  从第8行到第12行,创建xsd:ArrayOfProduct schema来表示具体的Product数组。在schema中没有出现不确定的内容。所以,最终Web服务客户端在反序列化Products数组的过程中没有遇到问题。

  含有空元素的数组

  含有空元素的数组的XML表示不同于.NET和WebSphere。考虑清单6中所示的Java Web服务方法。

  清单6. 返回含有空元素的数组的Java方法
 public String[] returnArrayWithNull() {
  String[] s = new String[3];
  s[0] = "ABC";
  s[1] = null;
  s[2] = "XYZ";
  return s;
 }
 
  这里的String元素s[1]被赋为空值。当.NET客户端调用这个部署到WebSphere平台上的Web服务方法的时候,该String数组被序列化成:

  清单7. 来源于WebSphere的Web服务响应消息
  <soapenv:Body>
  <returnArrayWithNullResponse xmlns="http://array.test">
  <returnArrayWithNullReturn>ABC</returnArrayWithNullReturn>
  <returnArrayWithNullReturn xsi:nil="true"/>
  <returnArrayWithNullReturn>XYZ</returnArrayWithNullReturn>
  </returnEmptyStringResponse>
  </soapenv:Body>
 
  数组中的第二个元素是设置xsi:nil="true"。这在Java中是非常有用的;Java客户端可以正确地将它反序列化成空的String值,该值是数组中的第二个元素。然而,.NET 客户端将其反序列化成长度为0的字符串而不是空的字符串。长度为0和空在面向对象的编程语言中是完全不同的概念。

  现在,考虑另一个部署在WebSphere上的Web服务方法,如清单8所示。

  清单8. 含有数组及其输入输出签名的Java方法
 public String[] processArray(String[] args) {
  //do something to the input array and return it back to the client
  return args;
 }
 
  这次,Web服务方法将数组作为输入,处理它,并将这个数组返回到客户端。假设.NET客户端发出含有空元素的数组,代码如清单9所示。

  清单9. .NET客户端发出含有空元素的数组
  TestArrayService proxy = new TestArrayService();
  string[] s = new string[3];
  s[0] = "abc";
  s[1] = null;
  s[2] = "xyz";
   // Console.WriteLine("the length of the input array = " +
s.GetLength(0));
  string[] ret = proxy.processArray(s);
   // Console.WriteLine("the length of the output array = " +
ret.GetLength(0));
 
  清单10展示了来源于.NET客户端的SOAP请求。

  清单10. .NET客户端发出的SOAP请求

  <soap:Body>
  <processArray xmlns="http://array.test">
  <args>abc</args>
  <args>xyz</args>
  </processArray>
  </soap:Body>
 
  .NET客户端发出的SOAP请求省略了空元素s[1]。结果,返回的数组的长度不再与原始数组的长度一致。如果这个数组的长度或者元素的索引对于客户端的逻辑来说是重要的,那么客户端将会失败。

  最佳的实例不是将含有空元素的数组传递到Web服务的客户端及服务器上。

  甚至原始的类型也能导致问题的出现

  XML Schema通过提供了大量的类型模型来减弱了互操作性。您可以构建WSDL消息及操作,因为XML Schema能够识别Web服务所使用的特定的数据类型。XSD提供了大量的类型以及简单的结构。但是,每种编程语言都有一套自己的本地数据类型。本地数据类型与XSD数据类型之间的一对一的映射是不存在的。因此,在翻译过程中可能丢失信息,或者接收端不可能生成某些本地数据类型的映射。

  无符号的数值类型(如xsd:unsignedInt、xsd:unsignedLong、xsd:unsignedShort和xsd:unsignedByte)是典型的例子。在.NET 中,uint、ulong、ushort和ubyte类型直接地映射到那些xsd类型中,但是Java语言没有无符号的数值类型。考虑到互操作性,不要公布那些在Web服务方法中的数值类型。取而代之,您可以创建封装器方法来公布并传递那些数值类型,如xsd:string(使用C#中的System.Convert.ToString)。

  对于xsd:decimal、xsd:double和xsd:float类型,每个平台可能有不同的精度支持。结果,如果您没有在整合之后测试Web服务那么可能会降低精度。

  无论数据类型是数值类型还是引用类型,信息传递的一方都可能出现问题。数值类型的对象位于栈中,但是引用类型的对象位于堆中。这意味着引用类型可能有空指针,但是数值类型不能有空值。如果XSD类型在一种语言中被映射成了数值类型,而在另一种语言中被映射成了引用类型,那么这可能导致问题的出现。例如 xsd:dateTime被映射成了System.DateTime,这是C#中的数值类型。它也被映射成了java.util.Calendar,这是Java中的引用类型。事实上,java.util.Date和java.util.Calendar都是引用类型。在Java中,当引用类型没有引用任何对象时将其赋空值,这是公共的操作。然而,如果.NET Web服务从Java客户端接收到数值类型为空值的数据时,将抛出System.FormatException。为了避免这个问题的出现,您可以定义复合类型来封装数值类型,并将这个复合类型置为空来表示空引用。

  结束语

  在本文中,您可以看到由于使用某些数据类型而产生的一些互操作性的问题。为了在使用数据类型时能够达到更好的互操作性,一般的规则是:

  ·尽量多地使用简单数据类型。完全避免使用那些异样的复合类型,如ArrayList、Tree,甚至公共的Hashtable。
  ·即使简单的数组通常都具有非常好的同Web服务的交互性,注意数组中的内容,确保数组中的元素在每个平台上的含义都是相同的,并且避免发出含有空元素的数组。
  ·注意每个平台都是如何实现一些本地原始类型的,如float、double和dates和times。

  在该系列文章中的下一部分,我将研究在Web服务互操作性上的命名空间所产生的影响。


提高J2EE技术与.NET之间的互操作性
 提高J2EE技术与.NET之间的互操作性(三)
 改善J2EE与.NET之间的互操作性(二)
 提高J2EE技术和.NET之间的互操作性(一)
 与XML语言协同运用的.NET工具
 实际项目中对SOA的困惑
 是什么把主机级别事务处理与Java或者.NET服务级别事物处理区别开来?
 .NET和J2EE该相互学习什么
 微软准备.NET 4.0——框架改进REST和MVC 支持JQuery
 浅析ASP.NET的五大数据控件
 .Net的精髓:XML和SOAP
 .NET平台的轻量级脚本引擎:NanoScript
 Bobby Woolf 谈J2EE体系结构和设计
 ASP.NET未来:简化开发 HTML5及性能提升
 J2EE的MVC体系结构及其设计模式

原文出处:http://www.ibm.com/developerworks/cn/webservices/ws-tip-j2eenet2.html
 
来源:IBM    作者:Wangming Ye    
 
 
 
 
 

.NET Web服务

 
Mono Project本周发布Moonlight 2,Silverlight的开源Linux实施。微软回应Adobe Flash,Silverlight是创建在线和离线的富应用的框架……
 
这一整年,我们发布了许多技巧来协助您创建更好的面向服务架构。为此我们认真筛选推荐一下5条技巧给您。希望可以起到查漏补缺的作用。
 
就像脱离浏览器运行Silverlight应用这个功能一样酷,微软通过推出运行离线OOB应用的功能而略胜一筹。这里对OOB离线的Silverlight应用……
 
UML从一开始就收到了很多批评。有些观察员认为UML语言有些臃肿,因为许多关系图很少使用,而有些关系图的功能又相互重叠……
 
统一建模语言(UML)是标准的可视化标注,可以用来表示软件工程的各个阶段。这个标准化的语言考虑到为使用它的不同组织和公司之间提供更广泛……

热门技术手册排行

 

随着开源技术越来越成熟,一个稍有开发经验的人通过学习就可以用开源的产品和技术构建一套可用的系统。对于从事软件开发的人员,尤其是对Java或动态语言相关领域的人来说,“开源”也许是他们最喜爱的单词。但是,很多时候我们需要的不仅仅是一个可用的系统,而是希望这个系统开发更简易、性能更高和扩展性更好等。这确实是一个令人头痛的问题。本指南很多地方都是点到为止,要深入了解相关信息的读者请借助参考资料、网站等自行挖掘。

 

本专题分六部分探讨SOA设计模式,当初设计面向服务架构的一大初衷就是降低服务间耦合度,由此提高服务的灵活性和自由度。

 

业务流程管理(business process management,bpm)不是一个新概念,甚至不是一个新名词。它是从相关的业务流程变革领域,如业务流程改进(bpi)、业务流程重组(bpr)、业务流程革新中发展起来的。流程管理技术也是从早期的工作流管理、eai、流程自动化、流程集成、流程建模、流程优化等技术中发展起来的。

 

TOAGF是一个架构框架,简而言之,TOGAF是一种协助发展,验收,运行,使用,和维护架构的工具。它是基于一个迭代(Iterative)的过程模型,支持最佳实践和一套可重用的现有架构资产。

 

云计算的概念越来越流行,Amazon、Google和IBM是第一批将云计算引入公众视线的公司。云计算就是新的Web2.0,一种既有技术上的市场绽放。

 

Mashup是一个非常cool的新的应用程序种类。如果你想真正的了解它们,我们需要回过头来看看你现在的计算机,其实它就是一个非常好的帮助你理解mashup的模型。现在开源的操作系统无疑是非常好的apis的集合或应用程序编程接口,帮助开发者去构建其应用程序。计算机本身也是一个很好的为用户提供接口的例子,键盘和鼠标可以被理解为你通过计算机的接口而使用的不同的应用程序。本技术手册为读者提供了一些相关信息,如果需要深入了解mashup,读者可以借助其他参考资源。

查看更多
 
 

登录TechTarget中国

关闭
本服务仅向TechTarget中国的会员开放,请登录或立即免费注册
电子邮件地址:
请输入您的电子邮件地址
密码:
下次自动登录