内容


Web 服务编程技巧和窍门

往返问题,引言

跨 JAX-RPC 维护数据完整性

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: Web 服务编程技巧和窍门

敬请期待该系列的后续内容。

此内容是该系列的一部分:Web 服务编程技巧和窍门

敬请期待该系列的后续内容。

这是一系列关于 往返(roundtripping)主题的技巧的第一篇。本技巧介绍了往返的概念,并首先提示了一些与现有的 JAX-RPC 映射规则有关的问题。一旦您了解了往返适用于哪些方面,随后的技巧将探究问题的更多细节。

往返是从一种表示映射到另一种表示,然后再映射回来的过程。在正常的情况下,您可能会以回到开始的地方而结束。例如,从阿拉伯数字系统中取出一个数字,比如说 9。将这个数字映射到罗马数字系统。您最后会得到 IX。现在,将其映射回阿拉伯数字系统,毫无疑问,您最后得到的是 9

但是,为什么是毫无疑问的呢?这之所以是毫无疑问的,是因为从阿拉伯数字映射到罗马数字,然后再映射回来,这在数学上称为是 一对一的(one-to-one)映成的(onto)关系。简而言之,对于每个阿拉伯数字,都有一个且只有一个罗马数字会映射到它。这对于从阿拉伯数字到罗马数字的映射同样成立。

如果情况不是这样会怎样呢?阿拉伯数字 0 又如何呢?因为根本就不存在从阿拉伯的 0 到罗马数字的映射。所以,尽管它看起来是毫无疑问的,但实际上却存在疑问。

在我继续讲解之前,让我先回答您可能提出的问题:我们为什么要担心往返?我将告诉您。一个典型的 Web 服务场景就是采用现有的应用程序,并将它作为一个 Web 服务来公开的。为了在 Java 世界里达到这个目的,首先您会从现有的 Java 代码生成一个 WSDL 文件(Java-to-WSDL)。然后,从这个 WSDL 文件,您要为这个服务(WSDL-to-Java)生成 Web 服务文件(Java 助手类、部署描述符,等等)。将这些材料打包成一个 EAR 文件,您就得到了原始的应用程序的 Web 服务。您以 Java 文件开始,将它映射到 WSDL,然后再将 WSDL 映射回 Java 文件。

上面的这一段话讨论的是服务器端。请注意,您同样也会在客户端完成 WSDL-to-Java 的步骤,但是从往返的角度来看,这并没有什么特殊的意义。在客户端您没有以 Java 代码开始,所以您没有做 Java-to-WSDL 这一步。实际上,即使客户端的 Java 代码与服务器端的 Java 代码完全不同,也是没有关系的。有关系的只是,客户端发送的消息对于服务器是可接受的,而且反之亦然。所以这些往返问题实际上仅仅使它们自己关心服务器。

请注意,到目前为止,我已经讨论了 Java-to-WSDL-to-Java 往返。您同样也可以考虑 WSDL-to-Java-to-WSDL 往返(实际上,它有更多的问题)。但是您将很少遇到从 WSDL 开始的往返的用况。所以,正如前面的一段中所述,我将专注于 Java-to-WSDL-to-Java 这一非常普遍的用况。

类似于 0 的情况

阿拉伯数字 0 不能映射到罗马数字系统。同样在 Java 语言中也有一些事物没有映射到 WSDL,像具有行为的对象;例如: InputStreamOutputStreamClass , Thread ,等等。请谨记,Web 服务通过有线线路发送 数据,而不是 Java 对象 —— 毕竟,SOAP 消息的接收者可能不是基于 Java 的,可能甚至都不是面向对象的。

不能映射到 WSDL 的 Java 对象集明显不能往返回到 Java 类型:所以,根据它们的性质,不存在与它们相关的往返问题。所以,在本技巧中我将不讨论它们。

类似于 9 的情况

有一组庞大的 Java 类型,它们的行为类似于阿拉伯数字 9,这些类型 确实可以映射到 WSDL。但是即使这组可以从 Java 映射到 WSDL 的数据类型也并不完全是可往返的。

在可以从 Java 映射到 WSDL 的集合中的大部分 Java 类型都正好映射回 Java 类型。例如,Java 代码的 int 映射到 XML 类型 xsd:int ,并且它映射回 Java 代码的 int 。因为大部分事物往返都正好,便容易落入这样的陷阱,就是假定 所有的事物返回都是正好的。但是有一个问题类型: java.util.Date

java.util.Date

Java 代码的 java.util.Date 映射到 XML schema 的 xsd:datetime 。但是然后 xsd:datetime 作为 java.util.Calendar 映射回 Java 代码。为什么 JAX-RPC 不能将 Date 映射到 xsd:date 然后再映射回 Date 呢?Calendar 到 datetime 再回到 Calendar 呢?这样就消除了这个往返问题,但是有两个非常充分的理由说明不能这样做。

  1. 维护可往返性不是 JAX-RPC 的目的。
  2. 与在 xsd:date 类型里所能够包含的信息相比, java.util.Date 具有更多的信息(例如,时间),所以 JAX-RPC 使用一个能够保存所有这方面的信息的 XML schema 类型: xsd:datetime

如何处理 Date

仅仅说“不”

绕过非往返 Date 问题的最简单的方法就是简单地避开它。改用 java.util.Calendar ,因为它 可以往返。此外,为了支持 Calendar 方法,很多 Date 方法都已经取消了,所以无论如何,您都很可能需要 Calendar 对象。

编写包装器

或许您不能够改变原始的 API。另外一个可供选择的办法就是编写使用 Date 的 API 的包装器代码。包装器代码将是 Web 服务,并且它将委派真正实现的所有调用。编写它们相当简单。例如,在 清单 1中给定原始的、不能改变的接口,您可以为它编写如 清单 2 中的包装器。

清单 1. 遗留 API

package com.ibm.developerWorks.roundtrip;
public class Legacy {
    public void setDate(java.util.Date date) {...};
}

清单 2. 原始遗留应用程序的 Web 服务包装器

package com.ibm.developerWorks.roundtrip;
public class Wrapper {
    private Legacy legacy = new Legacy();
    public void setDate(java.util.Calendar calendar) {
        legacy.setDate(calendar.getTime());
    }
}

修改映射元素据文件

J2EE 的 Web 服务(通常被称为 JSR-109)定义了映射元数据文件,它使您能够绕开某些 JAX-RPC 映射规则。随着将来的技巧进行调整,它将给出一些关于修改这个映射元数据文件来绕过往返问题的线索。

除了 java.util.Date 以外,还有其他的往返问题,我将在随后的技巧中更加详细地讨论它们。随着更多的更加深入细节的往返技巧进行调整。

总结

一个典型的 Web 服务场景就是采用现有的应用程序,并将它作为一个 Web 服务来公开。为了这样做,您将不得不作从 Java 类型到 WSDL 最后又回到 Java 类型的往返。在这个往返中,不必保留原始的构造。本技巧展示出,如果原始的 Java API 包括 java.util.Date ,那么作为往返结果的 API 将与原始的不相匹配。

有很多的方法来解决往返问题:您可以完全地回避它们;您可以编写原始实现的 Web 服务包装器,或者您还可以修改映射元数据文件(尽管本技巧没有详述映射元数据文件)。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=21477
ArticleTitle=Web 服务编程技巧和窍门: 往返问题,引言
publish-date=04012004