axis2数据绑定

尽管XML消息交换是Web服务的核心,但是大多数Web服务应用程序都不关心XML。 而是,这些应用程序希望交换特定于该应用程序的业务数据。 在这种情况下,XML只是一种用于表示支持Web服务接口的业务数据的格式。 XML为此很好地工作,因为XML提供了与平台无关的表示形式,可以通过各种工具来处理。 但是应用程序最终需要将XML与它们自己的内部数据结构进行相互转换,以在应用程序中使用数据。

数据绑定是用于处理XML与应用程序数据结构之间的这种转换的技术的术语。 可以为应用程序编写自定义数据绑定代码,但是大多数开发人员发现使用以通用方式处理转换的数据绑定框架更适用,适用于各种应用程序。 Apache Axis2 Web服务框架的主要优势之一是从一开始就设计为可与各种数据绑定框架一起使用。 您可以选择最适合您的数据绑定方法,并使用该方法来处理XML和数据结构之间的转换,同时使用Axis2框架(和扩展)来处理实际的Web服务工作。

本文向您展示如何将Axis2的数据绑定灵活性与示例代码一起用于使用支持的三种数据绑定实现的同一Web服务。 找出为什么您可能更喜欢其中一种数据绑定。

链接到Axis2

在本系列的上一篇文章中 ,您了解了Axis2用于XML消息处理的AXIOM文档模型。 AXIOM与其他文档模型的不同之处在于,AXIOM支持按需构建模型,而不是一次全部构建模型。 当使用数据绑定框架将XML与应用程序数据结构之间来回转换时,数据绑定XML通常只是AXIOM文档模型的虚拟部分。 除非出于某种原因(例如,使用WS-Security时进行加密或签名)需要该模型,否则不会将其扩展为完整的文档模型。

为了将应用程序与直接使用AXIOM隔离开来,Axis2支持从Web服务描述语言(WSDL)服务描述生成链接代码。 生成的链接代码使用您选择的数据绑定框架处理将数据结构与XML相互转换的细节,从而使您的应用程序可以直接访问数据结构。 Axis2还提供了一些其他方面的有限支持,即从现有代码生成WSDL。

Axis2为服务客户端和服务提供者生成链接代码。 客户端链接代码采用存根类的形式,它始终扩展Axis2 org.apache.axis2.client.Stub类。 提供程序(或服务器)链接代码采用特定于服务的实现框架以及实现org.apache.axis2.engine.MessageReceiver接口的消息接收器类的形式。 客户端和服务器链接代码的生成均由WSDL2Java工具处理。 接下来,您将看一下实际的链接代码,然后深入研究使用WSDL2Java工具的细节,并通过快速查看从现有代码开始的方法来完成本节。

客户端链接代码

客户端存根代码定义了应用程序代码调用服务操作的访问方法。 首先,您通常使用默认构造函数(如果您的服务端点始终与用于生成存根的WSDL中定义的端点相同)创建存根类的实例,或者使用不同的端点引用作为字符串。 创建存根的实例之后,可以选择使用基类org.apache.axis2.client.Stub类定义的方法来配置各种功能。 然后,您可以调用特定于服务的访问方法来实际调用操作。

清单1显示了一个示例,该示例说明了如何创建一个存根,并将服务端点(从WSDL中的端点)更改为客户端系统(本地主机)上的默认Tcpmon端口8800。 Tcpmon是监视Web服务消息交换的流行工具,因此在客户端代码中将此选项作为选项通常很有用。 创建存根实例后,超时值将从默认值更改(在调试提供程序代码时也很有用,因为您可以轻易超过20秒的标准超时时间),并调用服务方法。

清单1.客户端存根用法示例
LibraryStub stub = new LibraryStub("http://localhost:8800/axis2/services/library");
stub.getServiceClient().getOptions().setTimeoutInMilliseconds(10000000);
Types[] types = stub.getTypes();

清单1的代码显示了一个同步服务方法调用,其中客户端线程在该服务调用内阻塞,并且直到调用完成且结果可用时才返回。 Axis2还使用回调接口支持异步调用。 清单2显示了清单1的代码,该代码被修改为使用简单的异步调用(这很简单,因为应用程序代码只是等待操作完成,而不做任何有用的事情)。

清单2.客户端存根异步示例
LibraryStub stub = new LibraryStub("http://localhost:8800/axis2/services/library");
TypesCallback cb = new TypesCallback();
stub.startgetTypes(cb);
Type[] types;
synchronized (cb) {while (!cb.m_done) {try {cb.wait();} catch (Exception e) {}}types = cb.m_result;if (types == null) {throw cb.m_exception;}
}
...
private static class TypesCallback extends LibraryCallbackHandler
{private boolean m_done;private Types[] m_result;private Exception m_exception;public synchronized void receiveResultgetTypes(Type[] resp) {m_result = resp;m_done = true;notify();}public synchronized void receiveErrorgetTypes(Exception e) {m_exception = e;m_done = true;notify();}
}

使用清单2中使用的HTTP连接,响应通常立即返回给客户端。 在通过将请求与响应分离的传输进行操作(例如Java™消息服务(JMS)或简单邮件传输协议(SMTP))时,异步调用最为有用,因为在这种情况下,请求之间的时间可能会大大延迟发送以及何时收到响应。 当然,使用HTTP访问的服务也可能涉及大量的处理延迟。 对于具有此类延迟的HTTP服务,可以使用WS-Addressing来允许分离的响应,异步调用对于处理这些响应很有用。

除了存根类(如果有异步支持,则为回调处理程序类),还为客户端代码生成了一个接口。 接口定义与WSDL portType定义的操作匹配的服务方法。 存根实现此接口,并添加一些内部使用的专用方法。 您可以直接使用存根,如清单1和清单2所示 ,或者仅使用该接口仅查看那些属于服务定义的方法。 无论哪种方式,当您调用其中一种服务方法时,存根都会使用所选的数据绑定框架处理将请求数据对象转换为XML,然后将返回的XML转换为响应数据对象的过程。

如果您只想直接在客户端上使用XML,则根本不需要使用生成的客户端存根类。 相反,您可以使用org.apache.axis2.client.ServiceClient类。 这样做意味着您首先需要配置服务和操作,然后调用ServiceClient.createClient()方法来为该操作创建org.apache.axis2.client.OperationClient 。 为了方便起见,WSDL2Java工具(在本文稍后介绍)提供了一个选项,即使您直接使用XML,也可以生成存根类。 这种情况下生成的存根看起来很像数据绑定示例,只不过它传递了AXIOM元素而不是数据对象。

服务器链接代码

Axis2的服务器端链接代码是消息接收器,定义为Axis2服务配置的一部分。 此消息接收器必须实现org.apache.axis2.engine.MessageReceiver接口。 该接口定义了一个void receive(org.apache.axis2.context.MessageContext)方法。 当收到请求消息时,Axis2框架将调用此方法,然后该方法负责处理请求的所有处理(如果合适,还包括生成响应)。

如果直接使用XML(以AXIOM元素的形式),则可以将标准org.apache.axis2.receivers.RawXML*MessageReceiver类之一用于服务器端链接(其中*表示消息的类型)服务使用的交换)。 否则,您将使用生成的消息接收器类,该类在基于Axis2 AXIOM的接口和使用数据对象的服务代码之间进行调整。 该服务代码以框架实现的形式生成,其服务方法仅引发异常。 您需要将自己的代码添加到框架中以完成服务器端连接。

清单3显示了服务器端框架的一个示例(为了可读性而重新格式化),其中的getBook()方法保持生成状态,而getTypes()方法通过委派给实际的实现类来实现。

清单3.服务器框架示例
public class LibrarySkeleton
{private final LibraryServer m_server;public LibrarySkeleton() {m_server = new LibraryServer();}/*** Auto generated method signature** @param isbn* @return book value*/public com.sosnoski.ws.library.Book getBook(java.lang.String isbn) {//Todo fill this with the necessary business logicthrow new java.lang.UnsupportedOperationException("Please implement " +this.getClass().getName() + "#getBook");}/*** Get the types of books included in library.** @return types*/public com.sosnoski.ws.library.Type[] getTypes() {return m_server.getTypes();}
}

直接向此类添加代码的不利之处在于,如果服务接口发生更改,则需要重新生成该类并合并您的更改。 您可以通过使用单独的实现类来扩展生成的框架,从而避免覆盖框架方法而无需更改生成的代码,来避免这种情况。 为此,您需要更改生成的services.xml服务描述。 这很容易; 只需将骨架类名称替换为实现类名称即可。 本文后面介绍的数据绑定示例都使用单独的实现类方法。 您可以在“ 下载”部分中查看这些示例的Ant build.xml文件,以了解如何自动执行替换。

Axis2工具

Axis2提供了各种工具来帮助开发人员使用该框架。 其中最重要的工具是使您可以从WSDL服务定义中生成Java链接代码(在上一节中找到)并从现有Java代码中生成WSDL服务定义的工具。

从WSDL生成代码

Axis2提供了一个WSDL2Java工具,用于根据WSDL服务描述生成代码。 您可以通过将org.apache.axis2.wsdl.WSDL2Java类作为Java应用程序运行,或通过Ant任务,Maven插件或Eclipse或IDEA插件直接使用此工具。 选择太多的弊端在于,在功能和错误修复方面,替代方法通常落后于基本Java应用程序,因此通常最好直接运行Java应用程序(本文将介绍)。

WSDL2Java提供了许多不同的命令行选项,选项的数量随着时间的推移而增加。 Axis2文档包含对选项的完整引用,因此您仅在此处查看一些最重要的选项:

  • -o path设置输出类和文件的目标目录(默认为工作目录)
  • -p package-name为生成的类设置目标软件包(默认是从WSDL名称空间生成的)
  • -d name name-设置数据绑定框架(用于ADB的adb ,用于XMLBeans的xmlbeans,用于JiBX的jibx以及用于无数据绑定的none ;默认为adb )
  • -uw解开doc / lit-wrapped消息,仅用于受支持的框架(当前为ADB和JiBX)
  • -s仅生成同步客户端接口
  • -ss生成服务器端代码
  • -sd生成服务器端部署文件
  • -uri path设置WSDL的路径以生成服务

还有一些特定于特定数据绑定框架的WSDL2Java选项。 在本文后面的数据绑定示例中,您可以看到其中两个选项。

从代码生成WSDL

Axis2还提供了Java2WSDL工具,可用于从现有服务代码生成WSDL服务定义。 但是,此工具有很多限制,包括无法使用Java集合类以及在构造从Java类生成的XML时缺乏灵活性。 限制的部分原因是由于Web服务开发方式的变化而导致对该领域缺乏兴趣。

通常,从现有代码开始开发Web服务时,Web服务和SOA领域中的许多机构都不满意。 他们认为,当Web服务的整个原理是XML应该独立于实现时,从代码开始就鼓励将XML消息结构耦合到特定的实现。 这种担忧当然有一些实质,但也有一些相反的论点。 一是从头开始编写WSDL服务和XML模式定义所涉及的困难。 WSDL和模式都是复杂的标准,使用这些定义的可用工具需要对要有效使用的标准有很好的了解。 如果开发人员在没有标准基础的情况下使用它,则生成的WSDL和模式通常比从代码生成的WSDL和模式更混乱。 另一个问题严格可行。 开发人员通常具有现有代码来实现现在需要作为Web服务公开的功能,并且他们希望能够在不进行实质性更改的情况下使用该现有代码。 因此,在可预见的将来,从代码生成WSDL可能仍然是一个问题。

对于Java2WSDL的更强大的替代方法,可以尝试使用我开发的Jibx2Wsdl工具( 有关更多信息,请参见参考资料部分)。 Jibx2Wsdl从一个或多个提供的服务类生成一整套WSDL,模式和JiBX绑定定义。 它支持Java 5枚举和通用集合,同时保持与旧版Java虚拟机(JVM)的兼容性,并自动从Java源文件中导出Javadocs作为生成的WSDL和架构定义的文档。 Jibx2Wsdl还提供了广泛的自定义机制来控制如何从Java类派生服务和XML表示,这甚至允许将Java 5之前的集合与类型化数据一起使用。 尽管Jibx2Wsdl专门用于简化使用JiBX数据绑定框架(也是由我创建)的现有类作为Web服务的部署,但是生成的WSDL和模式与数据绑定无关。 您可以将它们与其他Java数据绑定框架甚至其他平台一起使用-生成所有内容,然后丢弃JiBX绑定并保留其余内容。

如果使用的是Java 5或更高版本,另一种选择是使用XML绑定的Java体系结构(JAXB)2.0和XML Web服务的Java API(JAX-WS)批注将数据对象和服务类公开为Web服务。 这些批注提供的自定义级别与Jibx2Wsdl所提供的级别不同,但是它们使您可以将配置信息直接嵌入到源代码中,这对某些开发人员来说很有吸引力。 Axis2从1.2版本开始提供对JAXB 2.0和JAX-WS的实验性支持,并且在将来的版本中将对此进行改进。 Jibx2Wsdl的未来版本可能还支持使用JAXB 2.0和JAX-WS批注作为自定义项。 (本系列的后续文章将更深入地介绍JAXB 2.0和JAX-WS,并回到那时从代码生成WSDL的主题。)

数据绑定比较

Axis2(从1.2版本开始)完全支持三种数据绑定替代方案,并且还在不断增加。 本文使用三个完全支持的数据绑定框架对示例代码进行了比较,并介绍了与Axis2一起使用时每个框架的一些优缺点。

清单4中显示的示例代码(也包含在“ 下载”部分的示例下载中)用于图书馆服务,该服务维护按主题类型组织的书籍的集合。 库上定义了一些操作,包括:

  • getBook
  • getTypes
  • addBook
  • getBooksByType

清单4提供了此服务的WSDL的局部视图,仅显示了getBook操作中涉及的部分。

清单4.库服务WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"xmlns:wns="http://ws.sosnoski.com/library/wsdl"xmlns:tns="http://ws.sosnoski.com/library/types"xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"><wsdl:types><schema elementFormDefault="qualified"targetNamespace="http://ws.sosnoski.com/library/wsdl"xmlns="http://www.w3.org/2001/XMLSchema"><import namespace="http://ws.sosnoski.com/library/types"/><element name="getBook"><complexType><sequence><element name="isbn" type="string"/></sequence></complexType></element><element name="getBookResponse"><complexType><sequence><element name="getBookReturn" minOccurs="0" type="tns:BookInformation"/></sequence></complexType></element>...</schema><schema elementFormDefault="qualified"targetNamespace="http://ws.sosnoski.com/library/types"xmlns="http://www.w3.org/2001/XMLSchema"><complexType name="BookInformation"><sequence><element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/><element name="title" type="string"/></sequence><attribute name="type" use="required" type="string"/><attribute name="isbn" use="required" type="string"/></complexType>...</schema></wsdl:types><wsdl:message name="getBookRequest"><wsdl:part element="wns:getBook" name="parameters"/></wsdl:message><wsdl:message name="getBookResponse"><wsdl:part element="wns:getBookResponse" name="parameters"/></wsdl:message>...<wsdl:portType name="Library"><wsdl:operation name="getBook"><wsdl:input message="wns:getBookRequest" name="getBookRequest"/><wsdl:output message="wns:getBookResponse" name="getBookResponse"/></wsdl:operation>...</wsdl:portType><wsdl:binding name="LibrarySoapBinding" type="wns:Library"><wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="getBook"><wsdlsoap:operation soapAction="urn:getBook"/><wsdl:input name="getBookRequest"><wsdlsoap:body use="literal"/></wsdl:input><wsdl:output name="getBookResponse"><wsdlsoap:body use="literal"/></wsdl:output></wsdl:operation>...</wsdl:binding>...</wsdl:definitions>

实际的服务实现代码很简单,用一个硬编码的书单填充一个库实例。 客户端代码按以下顺序执行一系列查询:

  1. 一本getBook
  2. 一个getTypes
  3. 一对addBook ,其中第二对返回SOAP Fault,以尝试添加重复的书本ID
  4. 一个getBooksByType

示例之间的实现细节有所不同,因为每个示例都使用适合该数据绑定的数据对象。 除非另有说明,否则显示的所有代码均与Axis2 1.1.1和1.2一致。 随着本文的发布,正在进行中的Axis2 1.3版本由于对与服务故障相对应的生成的异常类的命名进行了更改,因此需要对代码进行一些小的更改。 提供了两个版本的代码(请参见下载部分)。

在本文中,尽管提供的下载内容(请参见下载部分)包括客户端和服务器代码以及所有示例的Ant构建文件,但您仅查看客户端代码。 接下来,查看三个数据绑定框架的客户端代码,并了解每种方法的优缺点。

Axis2数据绑定

ADB是Axis2的数据绑定扩展。 与其他数据绑定框架不同,ADB代码仅可用于Axis2 Web服务。 此限制是对亚行的重要限制,但也具有一些优势。 由于ADB与Axis2集成在一起,因此可以针对Axis2的要求对代码进行优化。 一个例子是,ADB建立在Axis2核心的AXis对象模型(AXIOM)文档模型上(如本系列中的上一篇文章所述 )。 亚行还提供了其他数据绑定框架目前不具备的一些增强功能,包括自动附件处理。 WSDL2Java为ADB代码生成提供全面支持,包括生成与XML模式组件相对应的数据模型类。

ADB模式支持有一些限制。 在当前的Axis2 1.2版本中,这些限制包括架构功能,例如具有maxOccurs="unbounded"合成器,具有attributeFormDefault="qualified"架构定义以及一些类似的变体。 但是Axis2 1.2 ADB架构支持比Axis2 1.1发行版要好得多,并且在每个Axis2框架发行版之前,支持都可能会持续改善,直到支持所有主要架构功能。

ADB代码生成的基本形式使用直接模型,其中单独的类对应于每个操作所使用的输入和输出消息。 清单5显示了使用这种基本形式的ADB代码生成的示例应用程序的客户端代码中最有趣的部分。 客户机代码演示与ADB生成的类,如相互作用GetBookDocumentGetBookDocument.GetBook用于参数的类getBook()方法的调用,并且GetBookResponseDocumentBookInformation用于从该呼叫的返回类。

清单5. ADB客户端代码
// create the client stub
AdbLibraryStub stub = new AdbLibraryStub(target);// retrieve a book directly
String isbn = "0061020052";
GetBook gb = new GetBook();
gb.setIsbn(isbn);
GetBookResponse gbr = stub.getBook(gb);
BookInformation book = gbr.getGetBookReturn();
if (book == null) {System.out.println("No book found with ISBN '" + isbn + '\'');
} else {System.out.println("Retrieved '" + book.getTitle() + '\'');
}// retrieve the list of types defined
GetTypesResponse gtr = stub.getTypes(new GetTypes());
TypeInformation[] types = gtr.getGetTypesReturn();
System.out.println("Retrieved " + types.length + " types:");
for (int i = 0; i < types.length; i++) {System.out.println(" '" + types[i].getName() + "' with " +types[i].getCount() + " books");
}// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {AddBook ab = new AddBook();ab.setType("scifi");ab.setAuthor(new String[] { "Cook, Glen" });ab.setIsbn(isbn);ab.setTitle(title);stub.addBook(ab);System.out.println("Added '" + title + '\'');ab.setTitle("This Should Not Work");stub.addBook(ab);System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFaultException e) {System.out.println("Failed adding '" + title +"' with ISBN '" + isbn + "' - matches existing title '" +e.getFaultMessage().getBook().getTitle() + '\'');
}// create a callback instance
CallbackHandler cb = new CallbackHandler();// retrieve all books of a type asynchronously
GetBooksByType gbbt = new GetBooksByType();
gbbt.setType("scifi");
stub.startgetBooksByType(gbbt, cb);
long start = System.currentTimeMillis();
synchronized (cb) {while (!cb.m_done) {try {cb.wait(100);} catch (Exception e) {}}
}
System.out.println("Asynchronous operation took " +(System.currentTimeMillis()-start) + " millis");
if (cb.m_response != null) {BookInformation[] books = cb.m_response.getGetBooksByTypeReturn();...

清单5使用了-u WSDL2Java选项生成的代码,该代码特定于ADB。 使用此选项,将为每个消息和数据模型类生成一个单独的Java源文件。 如果不使用此选项,则ADB代码生成将所有这些类生成为生成的存根的静态内部类。 使用单独的类要容易得多,因此,如果使用ADB,则应指定-u选项。

代码生成的直接形式导致每个操作的输入和输出都有大量单独的类(与-u选项无关,后者只是以不同的方式组织相同的类)。 这些生成的消息类通常包含很少的数据(对于GetTypes类,甚至不包含)有用的数据,但是生成的方法签名需要这些数据。 幸运的是,还有另一种形式的代码生成适用于许多常见服务。

亚行展开

Web服务通常是基于现有编程API的方法调用形式开发的,在这种情况下,将现有API嵌入Web服务是很方便的。 这很容易做到; 毕竟,为服务定义的操作(从技术上来说,是为portType定义的,如果有人想挑剔的话)实质上等同于接口定义中的方法调用。 唯一的主要区别是该服务将输入和输出定义为XML消息,而不是调用参数和返回值。 因此,要将现有API嵌入到Web服务定义中,您只需要一个约定,以约定如何将调用参数和返回值表示为XML消息结构。

幸运的是,Microsoft®早在这方面就建立了约定,从而使我们其余的人不必自己做一些事情。 此约定称为包装文档/文字约定,是.NET在将方法调用公开为Web服务操作时使用的默认表示形式。 本质上,这种包装方法表示每个输入消息都是仅由一系列子元素组成的XML元素,每个输出消息都是具有单个子元素的XML元素。 除了完全的.NET互操作性之外,Microsoft实现还有其他一些技术细节并不是很重要,但是除了这些细节之外,用于库示例的消息(请参见清单4的部分视图)也遵循这种方法。

WSDL2Java支持在ADB代码生成中解包此类打包的doc / lit服务。 当将拆包与合适的WSDL服务定义一起使用时,生成的客户端存根(以及服务器框架)将更简单,更直接。 清单6显示了与清单5等效的客户机应用程序代码,但将-uw参数传递给WSDL2Java来生成未包装的接口。 清单6中消除了增加了清单5复杂性的消息类( GetTypes类除外),并且服务方法接受参数并直接返回结果,而不是嵌入消息类中。 在后台,ADB仍然会生成消息类并在生成的代码中使用它们,但是您的代码通常可以忽略这些类并直接使用数据。

清单6. ADB展开的客户端代码
// create the client stub
AdbUnwrapLibraryStub stub = new AdbUnwrapLibraryStub(target);// retrieve a book directly
String isbn = "0061020052";
BookInformation book = stub.getBook(isbn);
if (book == null) {System.out.println("No book found with ISBN '" + isbn + '\'');
} else {System.out.println("Retrieved '" + book.getTitle() + '\'');
}// retrieve the list of types defined
TypeInformation[] types = stub.getTypes(new GetTypes());
System.out.println("Retrieved " + types.length + " types:");
for (int i = 0; i < types.length; i++) {System.out.println(" '" + types[i].getName() + "' with " +types[i].getCount() + " books");
}// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {stub.addBook("scifi", isbn, new String[] { "Cook, Glen" }, title);System.out.println("Added '" + title + '\'');title = "This Should Not Work";stub.addBook("xml", isbn, new String[] { "Nobody, Ima" }, title);System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFaultException e) {System.out.println("Failed adding '" + title +"' with ISBN '" + isbn + "' - matches existing title '" +e.getFaultMessage().getBook().getTitle() + '\'');
}// create a callback instance
BooksByTypeCallback cb = new BooksByTypeCallback();// retrieve all books of a type asynchronously
stub.startgetBooksByType("scifi", cb);
long start = System.currentTimeMillis();
synchronized (cb) {while (!cb.m_done) {try {cb.wait(100L);} catch (Exception e) {}}
}
System.out.println("Asynchronous operation took " +(System.currentTimeMillis()-start) + " millis");
if (cb.m_books != null) {BookInformation[] books = cb.m_books;...

Axis2 1.3更新
在本文发表时,Axis2 1.3发行版已接近生产准备就绪。 本节中讨论的ADB展开问题已得到解决,因此,如果您能够开始使用Axis2 1.3代码,则使用ADB的体验将比早期版本的Axis2更好。 下载部分中包含本文的示例代码的1.3特定版本。

ADB展开支持的主要问题在于,它尚不完全稳定。 清单6的代码适合与Axis2 1.2一起使用,并且包含了一些原本用于Axis2 1.1.1中未包装的ADB的代码的重大改进。 但是WSDL2Java工具要求通过将数据类的内联模式移动到单独的模式文档中,来重组与其他示例一起使用的WSDL文档,以用于本示例。 更重要的是,清单6中显示的代码并不能全部工作。 该代码的最后一部分使用异步操作,由于生成的ADB客户端存根代码中的错误,在运行时由于类强制转换异常而失败。

到Axis2 1.2的后继版本发布时,应该基本消除ADB未解决的问题。 但是ADB并不是Axis2支持解包的唯一数据绑定框架。 JiBX还提供了展开支持,并且自Axis2 1.1.1版本以来,JiBX版本一直稳定。 在检查了Axis2数据绑定的其他主要选择之后,您可以在本文的后面再看一下JiBX客户端代码。

XMLBeans

XMLBeans是包含数据绑定层的常规XML处理框架。 它起源于BEA Systems项目,然后捐赠给Apache基金会。 XMLBeans是Axis2支持的第一种数据绑定形式,并且继续是使用Axis2的流行选择,尤其是与复杂模式定义一起使用时。

清单7显示了示例应用程序的XMLBeans客户端代码中最有趣的部分。 与基本(非展开式)ADB代码一样,每个操作的输入和输出都有单独的类。 但是XMLBeans与ADB的不同之处在于,为文档添加了一个类,其中包含输入或输出类( GetBookDocument ,除了GetBook类之外还有一个GetBookDocument )。 最终效果是使用XMLBeans而不是ADB时增加了一个对象创建层。 Axis2中没有对XMLBeans的解包支持,因此无法避免这种增加的对象层。 结果是XMLBeans生成的类要比其他数据绑定框架的等效类使用起来更复杂。

清单7. XMLBeans客户端代码
// create the client stub
XmlbeansLibraryStub stub = new XmlbeansLibraryStub(target);// retrieve a book directly
String isbn = "0061020052";
GetBookDocument gbd = GetBookDocument.Factory.newInstance();
GetBookDocument.GetBook gb = gbd.addNewGetBook();
gb.setIsbn(isbn);
gbd.setGetBook(gb);
GetBookResponseDocument gbrd = stub.getBook(gbd);
BookInformation book = gbrd.getGetBookResponse().getGetBookReturn();
if (book == null) {System.out.println("No book found with ISBN '" + isbn + '\'');
} else {System.out.println("Retrieved '" + book.getTitle() + '\'');
}// retrieve the list of types defined
GetTypesDocument gtd = GetTypesDocument.Factory.newInstance();
gtd.addNewGetTypes();
GetTypesResponseDocument gtrd = stub.getTypes(gtd);
TypeInformation[] types =gtrd.getGetTypesResponse().getGetTypesReturnArray();
System.out.println("Retrieved " + types.length + " types:");
for (int i = 0; i < types.length; i++) {System.out.println(" '" + types[i].getName() + "' with " +types[i].getCount() + " books");
}// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {AddBookDocument abd = AddBookDocument.Factory.newInstance();AddBookDocument.AddBook ab = abd.addNewAddBook();ab.setAuthorArray(new String[] { "Cook, Glen" });ab.setIsbn(isbn);ab.setTitle(title);ab.setType("scifi");stub.addBook(abd);System.out.println("Added '" + title + '\'');title = "This Should Not Work";ab.setTitle(title);stub.addBook(abd);System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFaultException e) {System.out.println("Failed adding '" + title +"' with ISBN '" + isbn + "' - matches existing title '" +e.getFaultMessage().getAddDuplicate().getBook().getTitle() +'\'');
}// create a callback instance
BooksByTypeCallback cb = new BooksByTypeCallback();// retrieve all books of a type asynchronously
GetBooksByTypeDocument gbtd =GetBooksByTypeDocument.Factory.newInstance();
gbtd.addNewGetBooksByType().setType("scifi");
stub.startgetBooksByType(gbtd, cb);
long start = System.currentTimeMillis();
synchronized (cb) {while (!cb.m_done) {try {cb.wait(100L);} catch (Exception e) {}}
}
System.out.println("Asynchronous operation took " +(System.currentTimeMillis()-start) + " millis");
if (cb.m_response != null) {BookInformation[] books =cb.m_response.getGetBooksByTypeResponse().getGetBooksByTypeReturnArray();...

Axis2 1.3更新
在本文发布时,Axis2 1.3发行版已接近生产就绪。 XMLBeans故障处理问题已在Axis2 1.3中修复。 下载部分中包含本文的示例代码的1.3特定版本。

清单7客户端和相应的服务器代码可以在Axis2 1.1.1上正确执行,但是由于在版本1.2的XMLBeans的错误处理代码生成中存在问题,当添加重复的书ID时,它会在预期的异常时失败。 在下一版本的Axis2中应纠正此问题。

尽管XMLBeans声称100%支持XML Schema,但是此声明的准确性只是解释问题。 的确,对于几乎所有的架构构造,XMLBeans都会生成一组Java类,可用于读写与该架构匹配的文档。 但是与本文中介绍的其他数据绑定框架不同,XMLBeans默认情况下对强制执行架构几乎没有作用。 例如,如果注释掉设置清单7代码中要添加的书的标题的行,那么XMLBeans会愉快地读写缺少必需的<title>元素的文档,因此是无效的文档。 清单8显示了此代码更改以及为添加请求发送到服务器的XML,以及在检索书籍时从服务器返回的XML。 在检索响应的情况下,XML文档包含<title>元素,但是使用xsi:nil="true"属性,该属性是架构不允许的,并且再次无效。

清单8. XMLBeans客户端和无效的文档
AddBookDocument abd = AddBookDocument.Factory.newInstance();AddBookDocument.AddBook ab = abd.addNewAddBook();ab.addAuthor("Cook, Glen");ab.setIsbn(isbn);ab.setType("scifi");
//            ab.setTitle(title);System.out.println("Validate returned " + abd.validate());stub.addBook(abd);...<addBook xmlns="http://ws.sosnoski.com/library/wsdl"><type>scifi</type><isbn>0445203498</isbn><author>Cook, Glen</author></addBook><getBooksByTypeResponse xmlns="http://ws.sosnoski.com/library/wsdl">...<getBooksByTypeReturn isbn="0445203498" type="scifi"><author xmlns="http://ws.sosnoski.com/library/types">Cook, Glen</author><title xmlns="http://ws.sosnoski.com/library/types" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/></getBooksByTypeReturn></getBooksByTypeResponse>

这是不设置所需值的简单情况。 对于更复杂的模式,XMLBeans生成的API可以隐藏更多的陷阱。 最近关于XMLBeans用户电子邮件列表的讨论涉及一种情况,其中必须将值交替添加到两个不同的列表中才能生成正确的输出。 因此,XMLBeans要求开发人员既了解模式又了解生成的代码与模式的关系,以确保有效的XML文档由应用程序代码构造。 数据绑定框架的主要好处之一通常是向开发人员隐藏这种模式细节,而XMLBeans在这方面肯定不足。

通过调用生成的类中包含的validate()方法,可以避免使用XMLBeans处理或生成无效的XML文档的问题。 如果使用XMLBeans,则至少应在测试和开发过程中对所有文档使用此检查。 但是,验证对性能有相当大的影响(正如您将在本系列的下一篇文章中看到的那样,即使不对每个文档都调用validate() ,XMLBeans的速度也已经很慢),因此许多应用程序应避免在生产中进行验证的开销部署。 验证在结果信息方面也相当有限。 为了找出验证失败的原因,您应该在错误的文档上运行标准架构验证。

吉宝

JiBX(我也开发了)是一个数据绑定框架,主要致力于使用现有的Java类,而不是从模式生成代码。 使用JiBX,您首先要创建一个绑定定义来定义如何将Java对象与XML相互转换,然后使用一种工具来编译该绑定,该工具通过添加实现转换的方法(作为字节码)来增强数据类文件。 然后,JiBX运行时框架使用这些添加的方法在XML和XML之间进行数据转换。

JiBX方法提供了一些独特的优点和缺点。 从好的方面来说,如果将Web服务接口添加到现有服务代码中,则JIBX允许您直接使用现有类。 Jibx2Wsdl工具对于此目的特别有用,因为它生成了将现有代码轻松部署为Axis2服务所需的一切。 您可以使用单个数据模型为同一类定义多个绑定,以同时使用不同XML版本的文档。 通过修改绑定,通常甚至可以在重构数据类时保留相同的XML表示形式。

清单9使用匹配message元素的类显示了JiBX客户端代码中有趣的部分。 该代码与清单5中所示的ADB类似,因此我将不对其进行详细介绍。 唯一显着的区别是,因为数据类和消息类都在用户的控制之下,所以很容易将便捷的构造函数(如AddBookRequest )和其他支持方法添加到与JiBX一起使用的类中。

清单9. JIBX客户端代码
// create the server instance
JibxLibraryStub stub = new JibxLibraryStub(target);// retrieve a book directly
String isbn = "0061020052";
GetBookResponse bresp = stub.getBook(new GetBookRequest(isbn));
Book book = bresp.getBook();
if (book == null) {System.out.println("No book found with ISBN '" + isbn + '\'');
} else {System.out.println("Retrieved '" + book.getTitle() + '\'');
}
isbn = "9999999999";
bresp = stub.getBook(new GetBookRequest(isbn));
book = bresp.getBook();
if (book == null) {System.out.println("No book found with ISBN '" + isbn + '\'');
} else {System.out.println("Retrieved '" + book.getTitle() + '\'');
}// retrieve the list of types defined
GetTypesResponse tresp = stub.getTypes(new GetTypesRequest());
Type[] types = tresp.getTypes();
System.out.println("Retrieved " + types.length + " types:");
for (int i = 0; i < types.length; i++) {System.out.println(" '" + types[i].getName() + "' with " +types[i].getCount() + " books");
}// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {AddBookRequest abr = new AddBookRequest("scifi", isbn, title,new String[] { "Cook, Glen" });stub.addBook(abr);System.out.println("Added '" + title + '\'');title = "This Should Not Work";abr = new AddBookRequest("scifi", isbn, title,new String[] { "Nobody, Ima" });System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFaultException e) {System.out.println("Failed adding '" + title +"' with ISBN '" + isbn + "' - matches existing title '" +e.getFaultMessage().getBook().getTitle() + '\'');
}// create a callback instance
BooksByTypeCallback cb = new BooksByTypeCallback();// retrieve all books of a type asynchronously
stub.startgetBooksByType(new GetBooksByTypeRequest("scifi"), cb);
long start = System.currentTimeMillis();
synchronized (cb) {while (!cb.m_done) {try {cb.wait(100);} catch (Exception e) {}}
}
System.out.println("Asynchronous operation took " +(System.currentTimeMillis()-start) + " millis");
if (cb.m_response != null) {Book[] books = cb.m_response.getBooks();

清单10显示了等效的JiBX未包装代码。 与ADB展开代码一样,理解和使用展开形式的服务调用比直接编写代码要容易得多。 JiBX和ADB版本之间唯一的显着区别是,在JiBX情况下,不需要传递任何值时就不需要创建对象,这是ADB对getTypes()调用所要求的。 JiBX解包的支持也比ADB版本更稳定,因为自Axis2 1.1.1起已完全支持它。

清单10. JIBX展开的客户端代码
// create the server instance
JibxUnwrapLibraryStub stub = new JibxUnwrapLibraryStub(target);// retrieve a book directly
String isbn = "0061020052";
Book book = stub.getBook(isbn);
if (book == null) {System.out.println("No book found with ISBN '" + isbn + '\'');
} else {System.out.println("Retrieved '" + book.getTitle() + '\'');
}// retrieve the list of types defined
Type[] types = stub.getTypes();
System.out.println("Retrieved " + types.length + " types:");
for (int i = 0; i < types.length; i++) {System.out.println(" '" + types[i].getName() + "' with " +types[i].getCount() + " books");
}// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {stub.addBook("scifi", isbn, new String[] { "Cook, Glen" }, title);System.out.println("Added '" + title + '\'');title = "This Should Not Work";stub.addBook("xml", isbn, new String[] { "Nobody, Ima" }, title);System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFaultException e) {System.out.println("Failed adding '" + title +"' with ISBN '" + isbn + "' - matches existing title '" +e.getFaultMessage().getBook().getTitle() + '\'');
}// create a callback instance
BooksByTypeCallback cb = new BooksByTypeCallback();// retrieve all books of a type asynchronously
stub.startgetBooksByType("scifi", cb);
long start = System.currentTimeMillis();
synchronized (cb) {while (!cb.m_done) {try {cb.wait(100L);} catch (Exception e) {}}
}
System.out.println("Asynchronous operation took " +(System.currentTimeMillis()-start) + " millis");
if (cb.m_books != null) {Book[] books = cb.m_books;

JiBX展开的支持在使用的类方面也与ADB不同。 使用解包的ADB时,仍会生成类并在幕后为所有消息元素使用类。 使用JiBX,在使用直接处理时必须定义与消息元素相对应的类,如清单9所示 ; 对于展开的处理,仅需要定义作为值传递的类,并将其包括在绑定定义中。 无论哪种方式,都需要在运行Axis2 WSDL2Java工具之前创建JiBX绑定定义,并且需要使用-Ebindingfile命令行参数来传递它。

至少在Web服务方面,JiBX绑定方法的最大缺点可能是,JiBX当前为从XML模式定义中进行的工作提供了较弱的支持。 即使是对Xsd2Jibx工具形式的对模式的弱支持,也没有集成到Axis2 WSDL2Java代码生成中。 这意味着您需要先创建Java数据类和绑定定义,然后才能运行WSDL2Java来生成Axis2链接代码。 JiBX所需的字节码增强步骤在某些环境中也可能会出现问题,因为通常需要在应用程序构建时完成它,并且导致代码出现在没有源代码的类中。

如本节开头所述,JiBX数据绑定提供了一些独特的好处。 In terms of Axis2 usage, JiBX also provides an advantage over the other frameworks in that it's supported with bug-fix releases that can be plugged into Axis2 releases to correct problems found after the release (see Get products and technologies in the Related topics section for details). For the other frameworks, the only way to obtain bug fixes is by moving to the nightly builds of Axis2, which can often lead to other problems. In the future, JiBX is expected to offer solid code and binding generation from schema support. When this is available, JiBX should be an excellent all-around data-binding alternative to Axis2. Until then, it's of most benefit when working from existing Java code, where the Jibx2Wsdl tool provides excellent support.

摘要

Axis2 currently provides full support for three different data-binding frameworks:

  • ADB is designed specifically for Axis2 and can only be used in the Axis2 environment. As of the Axis2 1.3 release, it provides good — and growing — support for code generation from schema. It also supports convenient unwrapped service methods and automatic attachment handling, making it a top choice when working from existing WSDL service definitions.
  • XMLBeans provides the most complete support for modeling schema structures in generated Java code. But it creates the most complex Java model for a given schema and doesn't support unwrapped service methods for a simpler interface. By default, it also doesn't enforce even basic schema structure rules on either input or output XML documents, making it easy for invalid XML documents to be accidentally created or accepted for processing.
  • JiBX is the only alternative that supports working with existing Java classes. It also provides excellent support for unwrapped service methods. But the JiBX support integrated into Axis2 doesn't handle code generation from schema, and even the separate code generation from schema support provided by the JiBX tools currently provides only limited schema support.

It's great that Axis2 offers a choice between these data-binding frameworks, because there's no single best choice for all needs. In the future, Axis2 will also provide full support for JAXB 2.0, which I'll cover as part of this series in an upcoming article about the related JAX-WS 2.0. Knowing the strengths and weaknesses of each framework can help you make the best choice for your needs and alert you to potential problem areas before you find them in production. In the next article in this series, you learn about another aspect of comparison for the Axis2 data-binding frameworks: performance.


翻译自: https://www.ibm.com/developerworks/opensource/library/j-java3/index.html

axis2数据绑定

axis2数据绑定_Axis2数据绑定相关推荐

  1. android数据绑定_Android数据绑定

    android数据绑定 With the introduction of Android M, one big change that's come slightly less noticed is ...

  2. android数据绑定_Android数据绑定高级概念

    android数据绑定 In this tutorial we'll look into some other tricky usages of Data Binding in our applica ...

  3. Vue学习记录04--单项数据绑定双向数据绑定

    1.单项数据绑定 只能从data流向页面 2.双向数据绑定 v-model 只能在输入属性的标签里使用(如input) 不仅可以从data流向页面,也能从⻚⾯表单元素(输⼊元素)流向data

  4. 数据绑定(Binding)

    Windows Presentation Foundation (WPF) 中的数据绑定为应用程序提供了一种简单.一致的数据表示和交互方法.元素能够以公共语言运行时 (CLR) 对象和 XML 形式绑 ...

  5. Angular4.0从入门到实战打造在线竞拍网站学习笔记之四--数据绑定管道

    Angular4.0基础知识之组件 Angular4.0基础知识之路由 Angular4.0依赖注入 Angular4.0数据绑定&管道 数据绑定 数据绑定允许你将组件控制器的属性和方法与组件 ...

  6. 【JetPack】数据绑定 DataBinding 简介 ( 使用要求 | Gradle 版本 | 定义数据类 | 定义数据绑定布局 | Activity 数据绑定 | 绑定类生成规则 )

    文章目录 I . 数据绑定 简介 II . 数据绑定 使用前提 ( 环境支持 ) III . 数据绑定 使用流程 一 : 启用数据绑定 IV . 数据绑定 使用流程 二 : 定义数据类 V . 数据绑 ...

  7. vue 双向数据绑定的实现学习(一)

    前言:本系列学习笔记从以下几个点展开 什么是双向数据绑定 双向数据绑定的好处 怎么实现双向数据绑定 实现双向数据数据绑定需要哪些知识点 数据劫持 发布订阅模式 先看看我们要实现的目标是什么,如下动图: ...

  8. 快速开发基于 HTML5 网络拓扑图应用之 DataBinding 数据绑定篇

    前言 发现大家对于我从 json 文件中直接操作节点属性来控制界面的动态变化感到比较好奇,所以这篇就针对数据绑定以及如何使用这些绑定的数据做一篇说明,我写了一个简单的例子,基于机房工控的服务器上设备的 ...

  9. DataBinder.Eval数据绑定中的使用

    DataBinder.Eval (Object, String) 在运行时计算数据绑定表达式. DataBinder.Eval (Object, String, String) 在运行时计算数据绑定表 ...

最新文章

  1. 如何从文件内容创建Java字符串?
  2. 改造消费方解决地址硬编码问题
  3. MSMQ(MicroSoft Message Queue,微软消息队列)
  4. js去除字符串数字前面的0_JS正则里面“?”的用处
  5. 基于Docker快速搭建ELK
  6. 底大一级压死人!华为Mate 30 Pro主摄CMOS或将达到1/1.5英寸
  7. linux java缓存失效_转载:Linux服务器Cache占用过多内存导致系统内存不足最终java应用程序崩溃解决方案...
  8. 流量分析的瑞士军刀:Zeek
  9. 原始套接字AF_PACKET用法尝试
  10. android获取用户点击的坐标
  11. centos7下yum安装mysql_CentOS7下使用YUM安装MySQL5.6-Go语言中文社区
  12. 郑州大学远程教育学院C语言程序设计题库(二)
  13. jsp分页代码mysql_jsp分页(jsp分页完整代码)
  14. linux系统配置Vim命令,怎么在LINUX操作系统中安装和配置VIM?
  15. 2018湘潭大学程序设计竞赛【E】
  16. Excel单元格保护
  17. 【Java每日面试题】大厂是如何设计秒杀系统的,渣本Java开发小伙如何一步步成为架构师
  18. 《杀死一只知更鸟》读后感
  19. labuladong的算法小抄_学会了回溯算法,我终于会做数独了
  20. 二叉树:二叉树的最近公共祖先

热门文章

  1. 怎样创建淘宝鱼塘,怎样利用鱼塘拉新,怎样利用鱼塘管理好老客户?
  2. go语言基础 数学包 math
  3. 为什么运营商大数据可以精准获客?
  4. BUUCTF VN2020 公开赛 Misc(复现)
  5. Ubuntu 测试两台电脑之间的网速
  6. rj45插座尺寸图_rj45插座组成部分及使用说明
  7. JAVA课程设计——植物大战僵尸(团队)
  8. Dev C++快捷操作指令
  9. VR沉浸感和交互作用原理
  10. 《游戏改变世界》——在枯燥的学习中也体验到游戏中的心流~