Java Web 服务: Axis2 中的 JAXB 和 JAX-WS(转)

Apache Axis2 支持各种数据绑定技术,包括官方 Java™ 标准 JAXB 2.x。Axis2 还支持针对 Web 服务配置的 Java 标准 JAX-WS 2.x,作为其自有的配置技术的替代选择。Dennis Sosnoski 将继续他的 Java Web 服务 系列,向您演示如何将这两种 Java 标准用于 Axis2,并讨论 Axis2 对这些标准的当前支持存在哪些限制。
早期的 Apache Axis 建立在第一个面向 Web 服务的 Java 标准 JAX-RPC 的基础之上。事实证明,这并不是一个很好的方法,因为 JAX-RPC 限制了 Axis 代码的内部设计,而且造成了性能问题并缺乏灵活性。JAX-RPC 还对 Web 服务开发的方向作出了假设,而这在后来被证明是错误的。

在开始 Axis2 开发工作时,已经着手研究 JAX-RPC 的替代选择,因此,Axis2 在设计时已经考虑到了足够的灵活性,使其能够在基础框架之上实现对替代 Web 服务标准的支持。最新的 Axis2 版本同时实现了对 JAXB 2.x Java XML 数据绑定标准和替代了 JAX-RP 的 JAX-WS 2.x Java Web 服务标准的支持。本文将展示如何将 JAXB 和 JAX-WS 用于 Axis2 并找出 Axis2 对这些标准的当前支持中存在的一些限制。

Axis2 中的 JAXB

Axis2 实现了对 JAXB 2.x 的支持,将它作为数据绑定替代选择的其中之一,您可以在使用 WSDL2Java 从 Web Services Description Language (WSDL) 服务定义中生成代码时进行选择。(参见 “Java Web Services: Axis2 Data Binding” 获得有关其他主要替代选择的讨论)。和大多数其他替代选择一样,使用 JAXB 2.x 从 WSDL 中生成的代码创建了一组链接(linkage)类和一组数据模型类。这些链接类,包括一个客户端 stub 和一个服务器端消息接收器,充当应用程序代码和 Axis2 之间的接口。数据模型类表示实际的消息数据。

JAXB 2.x 使用数据模型类中的注释来控制数据与 XML 之间的转换方式。注释方法允许您在无需修改源代码或重新编译类的情况下在运行时使用不同的 JAXB 实现。由 JAXB 实现负责从数据模型类访问注释信息并在执行 XML 转换时应用这些注释。

代码下载(参见 下载)提供了一个演示在 Axis2 中使用 JAXB 的示例应用程序,位于 jaxb 目录中。这个应用程序是本系列前一篇文章中的简单的库管理服务的另一个版本(包括 “Axis2 Data Binding” 中的数据绑定比较)。WSDL 服务定义定义了四个操作:

getBook 用来检索由 International Standard Book Number (ISBN) 标识的某本特定图书的细节信息
getBooksByType 用来检索某一特定类型的所有图书的细节信息
getTypes 用于查找可用的图书类型
addBook 用于将新书添加到库中
清单 1 显示的是经过大量编辑的 WSDL,只包含了与 getBook 操作有关的部分:

清单 1. 库服务 WSDL

Java代码
  1. <wsdl:definitions targetNamespace= "http://ws.sosnoski.com/library/wsdl"   
  2.     xmlns:wns="http://ws.sosnoski.com/library/wsdl"   
  3.     xmlns:tns="http://ws.sosnoski.com/library/types"   
  4.     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"   
  5.     xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" >  
  6.   <wsdl:types>  
  7.     
  8.     <schema elementFormDefault="qualified"   
  9.         targetNamespace="http://ws.sosnoski.com/library/wsdl"   
  10.         xmlns="http://www.w3.org/2001/XMLSchema" >  
  11.         
  12.       <import  namespace= "http://ws.sosnoski.com/library/types"   
  13.           schemaLocation="types.xsd" />  
  14.           
  15.       <element name="getBook" >  
  16.         <complexType>  
  17.           <sequence>  
  18.             <element name="isbn"  type= "string" />  
  19.           </sequence>  
  20.         </complexType>  
  21.       </element>  
  22.         
  23.       <element name="getBookResponse" >  
  24.         <complexType>  
  25.           <sequence>  
  26.             <element name="getBookReturn"  minOccurs= "0"  type= "tns:BookInformation" />  
  27.           </sequence>  
  28.         </complexType>  
  29.       </element>  
  30.       ...  
  31.       
  32.     </schema>  
  33.   
  34.   </wsdl:types>  
  35.   
  36.   <wsdl:message name="getBookRequest" >  
  37.     <wsdl:part element="wns:getBook"  name= "parameters" />  
  38.   </wsdl:message>  
  39.   
  40.   <wsdl:message name="getBookResponse" >  
  41.     <wsdl:part element="wns:getBookResponse"  name= "parameters" />  
  42.   </wsdl:message>  
  43.   ...  
  44.   
  45.   <wsdl:portType name="Library" >  
  46.   
  47.     <wsdl:operation name="getBook" >  
  48.       <wsdl:input message="wns:getBookRequest"  name= "getBookRequest" />  
  49.       <wsdl:output message="wns:getBookResponse"  name= "getBookResponse" />  
  50.     </wsdl:operation>  
  51.     ...  
  52.   
  53.   </wsdl:portType>  
  54.   
  55.   <wsdl:binding name="LibrarySoapBinding"  type= "wns:Library" >  
  56.   
  57.     <wsdlsoap:binding style="document"   
  58.       transport="http://schemas.xmlsoap.org/soap/http" />  
  59.   
  60.     <wsdl:operation name="getBook" >  
  61.       
  62.       <wsdlsoap:operation soapAction="urn:getBook" />  
  63.         
  64.       <wsdl:input name="getBookRequest" >  
  65.         <wsdlsoap:body use="literal" />  
  66.       </wsdl:input>  
  67.         
  68.       <wsdl:output name="getBookResponse" >  
  69.         <wsdlsoap:body use="literal" />  
  70.       </wsdl:output>  
  71.         
  72.     </wsdl:operation>  
  73.     ...  
  74.   
  75.   </wsdl:binding>  
  76.   
  77.   <wsdl:service name="jaxb-library" >  
  78.   
  79.     <wsdl:port binding="wns:LibrarySoapBinding"  name= "library" >  
  80.       <wsdlsoap:address location="http://localhost:8080/axis2/services/jaxb-library" />  
  81.     </wsdl:port>  
  82.   
  83.   </wsdl:service>  
  84.   
  85. </wsdl:definitions>  
<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"
          schemaLocation="types.xsd"/>
        
      <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>

  </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:service name="jaxb-library">

    <wsdl:port binding="wns:LibrarySoapBinding" name="library">
      <wsdlsoap:address location="http://localhost:8080/axis2/services/jaxb-library"/>
    </wsdl:port>

  </wsdl:service>

</wsdl:definitions>


Axis2 的 JAXB 支持应该进行扩展,以生成未封装的操作方法(为了方便编程,封装到消息中的值被转换为方法参数 — 再一次建议您参考 “Java Web 服务:Axis2 Data Binding”,获得有关封装接口和未封装接口的讨论。但是使用 WSDL2Java 工具的未封装支持,不管在当前的 Axis2 代码中,还是最近几个发行版中,都不适合这个例子。至少在目前,封装操作方法是惟一可以将 JAXB 用于 Axis2 代码生成的方法(但请立刻参考一下 JAX-WS 讨论 了解另一种替代方法)。对于封装操作接口,每个服务方法都对操作使用一个与输入消息匹配的单一对象参数,并为操作返回一个与输出消息匹配的对象。

附带的代码提供了服务和测试客户机的实际实现,开始处理由运行的 WSDL2Java 生成的类。与本系列早期文章的样例代码相同,下载部分包括用于通过 Apache Ant 构建样例的 build.properties 和 build.xml 文件(位于 jaxb 目录)。您首先需要编辑 build.properties 文件,以将路径设置为您的 Axis2 安装(并修改其他设置,如果系统需要的话)。随后可以在一个打开到 jaxb 目录的控制台中输入 ant 以运行 WSDL2Java,编译附带的和生成的代码,并为服务器部署构建 AAR 文件。要进行尝试,首先将生成的 AAR 文件部署到您的 Axis2 服务器安装并在控制台中输入 ant run。

客户端 JAXB 使用

测试客户机使用作为命令行参数传递进来的服务端点参数创建了一个服务 stub 实例,然后依次执行 5 个服务调用:

获得有关某本书的细节。
获得库中的图书类型。
向库添加一本新书(如果该书已经存在的话,此操作将失败,当客户机在未重启服务器的情况下运行超过一次时,也会出现同样的错误)。
如果上一步骤成功,那么尝试使用相同 ISBN 添加另一本书(这个操作应当永远都是失败的)。
获得有关某一特定类型的所有图书的信息。
清单 2 展示了完整的测试客户机代码。可以看到用于每个操作的封装器对象中的服务接口的封装特性,比如调用 getTypes 操作所需的 GetTypes 对象(即使没有为该操作提供输入数据)和由调用返回的 GetTypesResponse 对象。

清单 2. JAXB 测试客户机代码

Java代码
  1. public   class  WebServiceClient  
  2. {  
  3.     public   static   void  main(String[] args)  throws  Exception {  
  4.           
  5.         // check for required command line parameters   
  6.         if  (args.length <  3 ) {  
  7.             System.out.println("Usage:\n  java "  +  
  8.                 "com.sosnoski.ws.library.jaxb.WebServiceClient host port path" );  
  9.             System.exit(1 );  
  10.         }  
  11.           
  12.         // create the client stub   
  13.         String target = "http://"  + args[ 0 ] +  ":"  + args[ 1 ] + args[ 2 ];  
  14.         System.out.println("Connecting to "  + target);  
  15.         JaxbLibraryStub stub = new  JaxbLibraryStub(target);  
  16.           
  17.         // retrieve a book directly   
  18.         String isbn = "0061020052" ;  
  19.         GetBook gb = new  GetBook();  
  20.         gb.setIsbn(isbn);  
  21.         GetBookResponse gbr = stub.getBook(gb);  
  22.         BookInformation book = gbr.getGetBookReturn();  
  23.         if  (book ==  null ) {  
  24.             System.out.println("No book found with ISBN '"  + isbn + '\ '' );  
  25.         } else  {  
  26.             System.out.println("Retrieved '"  + book.getTitle() + '\ '' );  
  27.         }  
  28.           
  29.         // retrieve the list of types defined   
  30.         GetTypesResponse gtr = stub.getTypes(new  GetTypes());  
  31.         List<TypeInformation> types = gtr.getGetTypesReturn();  
  32.         System.out.println("Retrieved "  + types.size() +  " types:" );  
  33.         for  ( int  i =  0 ; i < types.size(); i++) {  
  34.             TypeInformation type = types.get(i);  
  35.             System.out.println(" '"  + type.getName() +  "' with "  +  
  36.                 type.getCount() + " books" );  
  37.         }  
  38.           
  39.         // add a new book   
  40.         String title = "The Dragon Never Sleeps" ;  
  41.         isbn = "0445203498" ;  
  42.         try  {  
  43.             AddBook ab = new  AddBook();  
  44.             ab.setType("scifi" );  
  45.             ab.setIsbn(isbn);  
  46.             ab.getAuthor().add("Cook, Glen" );  
  47.             ab.setTitle(title);  
  48.             stub.addBook(ab);  
  49.             System.out.println("Added '"  + title + '\ '' );  
  50.             title = "This Should Not Work" ;  
  51.             ab.setTitle(title);  
  52.             stub.addBook(ab);  
  53.             System.out.println("Added duplicate book - should not happen!" );  
  54.         } catch  (AddDuplicateFault e) {  
  55.             System.out.println("Failed adding '"  + title +  
  56.                 "' with ISBN '"  + isbn +  "' - matches existing title '"  +  
  57.                 e.getFaultMessage().getBook().getTitle() + '\'' );  
  58.         }  
  59.           
  60.         // get all books of a type   
  61.         GetBooksByType gbbt = new  GetBooksByType();  
  62.         gbbt.setType("scifi" );  
  63.         GetBooksByTypeResponse gbbtr = stub.getBooksByType(gbbt);  
  64.         List<BookInformation> books = gbbtr.getGetBooksByTypeReturn();  
  65.         System.out.println("Retrieved "  + books.size() +  " books of type 'scifi':" );  
  66.         for  ( int  i =  0 ; i < books.size(); i++) {  
  67.             System.out.println(" '"  + books.get(i).getTitle() + '\ '' );  
  68.         }  
  69.     }  
  70. }  
public class WebServiceClient
{
    public static void main(String[] args) throws Exception {
        
        // check for required command line parameters
        if (args.length < 3) {
            System.out.println("Usage:\n  java " +
                "com.sosnoski.ws.library.jaxb.WebServiceClient host port path");
            System.exit(1);
        }
        
        // create the client stub
        String target = "http://" + args[0] + ":" + args[1] + args[2];
        System.out.println("Connecting to " + target);
        JaxbLibraryStub stub = new JaxbLibraryStub(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());
        List<TypeInformation> types = gtr.getGetTypesReturn();
        System.out.println("Retrieved " + types.size() + " types:");
        for (int i = 0; i < types.size(); i++) {
            TypeInformation type = types.get(i);
            System.out.println(" '" + type.getName() + "' with " +
                type.getCount() + " books");
        }
        
        // add a new book
        String title = "The Dragon Never Sleeps";
        isbn = "0445203498";
        try {
            AddBook ab = new AddBook();
            ab.setType("scifi");
            ab.setIsbn(isbn);
            ab.getAuthor().add("Cook, Glen");
            ab.setTitle(title);
            stub.addBook(ab);
            System.out.println("Added '" + title + '\'');
            title = "This Should Not Work";
            ab.setTitle(title);
            stub.addBook(ab);
            System.out.println("Added duplicate book - should not happen!");
        } catch (AddDuplicateFault e) {
            System.out.println("Failed adding '" + title +
                "' with ISBN '" + isbn + "' - matches existing title '" +
                e.getFaultMessage().getBook().getTitle() + '\'');
        }
        
        // get all books of a type
        GetBooksByType gbbt = new GetBooksByType();
        gbbt.setType("scifi");
        GetBooksByTypeResponse gbbtr = stub.getBooksByType(gbbt);
        List<BookInformation> books = gbbtr.getGetBooksByTypeReturn();
        System.out.println("Retrieved " + books.size() + " books of type 'scifi':");
        for (int i = 0; i < books.size(); i++) {
            System.out.println(" '" + books.get(i).getTitle() + '\'');
        }
    }
}



如果将 清单 2 与 “Java Web Services: Axis2 Data Binding” 中的客户机代码示例加以比较,会发现它非常类似于 JiBX 和 Axis Data Binding (ADB) 封装例子,主要区别在于 JAXB 封装器类使用 Java 5 类型列表(typed lists)而不是数组(JiBX 数据绑定支持的另一个替换选择,但是不受 ADB 支持)。

服务器端使用

库服务的服务器端代码包含两个类,其中一个实际实现库处理,另一个可适应 Axis2 所期望的服务接口。实际的实现代码对于不同的数据绑定几乎都是相同的,只需要根据生成的数据模型表示做一些微小的修改。清单 3 展示了更加有趣的服务接口类。和在客户端一样,封装的接口要求应用程序代码从收到的封装器对象中提取数据,并构造将要发送的封装器对象。

清单 3. JAXB 服务器代码

Java代码
  1. public   class  JaxbLibraryImpl  extends  JaxbLibrarySkeleton  
  2. {  
  3.     private   final  BookServer m_server;  
  4.       
  5.     public  JaxbLibraryImpl() {  
  6.         m_server = new  BookServer();  
  7.     }  
  8.       
  9.     public  AddBookResponse addBook(AddBook req)  throws  AddDuplicateFault {  
  10.         BookInformation prior = m_server.getBook(req.getIsbn());  
  11.         if  (prior ==  null ) {  
  12.             BookInformation book = new  BookInformation();  
  13.             book.getAuthor().addAll(req.getAuthor());  
  14.             book.setIsbn(req.getIsbn());  
  15.             book.setTitle(req.getTitle());  
  16.             book.setType(req.getType());  
  17.             AddBookResponse rsp = new  AddBookResponse();  
  18.             rsp.setAddBookReturn(m_server.addBook(book));  
  19.             return  rsp;  
  20.         } else  {  
  21.             AddDuplicateFault e =  
  22.                 new  AddDuplicateFault( "Book already present with matching ISBN" );  
  23.             AddDuplicate ad = new  AddDuplicate();  
  24.             ad.setBook(prior);  
  25.             e.setFaultMessage(ad);  
  26.             throw  e;  
  27.         }  
  28.     }  
  29.   
  30.     public  GetBookResponse getBook(GetBook req) {  
  31.         BookInformation book = m_server.getBook(req.getIsbn());  
  32.         GetBookResponse rsp = new  GetBookResponse();  
  33.         rsp.setGetBookReturn(book);  
  34.         return  rsp;  
  35.     }  
  36.   
  37.     public  GetBooksByTypeResponse getBooksByType(GetBooksByType req) {  
  38.         GetBooksByTypeResponse rsp = new  GetBooksByTypeResponse();  
  39.         rsp.getGetBooksByTypeReturn().addAll(m_server.getBooksByType(req.getType()));  
  40.         return  rsp;  
  41.     }  
  42.   
  43.     public  GetTypesResponse getTypes(GetTypes req) {  
  44.         GetTypesResponse rsp = new  GetTypesResponse();  
  45.         rsp.getGetTypesReturn().addAll(m_server.getTypes());  
  46.         return  rsp;  
  47.     }  
  48. }  
public class JaxbLibraryImpl extends JaxbLibrarySkeleton
{
    private final BookServer m_server;
    
    public JaxbLibraryImpl() {
        m_server = new BookServer();
    }
    
    public AddBookResponse addBook(AddBook req) throws AddDuplicateFault {
        BookInformation prior = m_server.getBook(req.getIsbn());
        if (prior == null) {
            BookInformation book = new BookInformation();
            book.getAuthor().addAll(req.getAuthor());
            book.setIsbn(req.getIsbn());
            book.setTitle(req.getTitle());
            book.setType(req.getType());
            AddBookResponse rsp = new AddBookResponse();
            rsp.setAddBookReturn(m_server.addBook(book));
            return rsp;
        } else {
            AddDuplicateFault e =
                new AddDuplicateFault("Book already present with matching ISBN");
            AddDuplicate ad = new AddDuplicate();
            ad.setBook(prior);
            e.setFaultMessage(ad);
            throw e;
        }
    }

    public GetBookResponse getBook(GetBook req) {
        BookInformation book = m_server.getBook(req.getIsbn());
        GetBookResponse rsp = new GetBookResponse();
        rsp.setGetBookReturn(book);
        return rsp;
    }

    public GetBooksByTypeResponse getBooksByType(GetBooksByType req) {
        GetBooksByTypeResponse rsp = new GetBooksByTypeResponse();
        rsp.getGetBooksByTypeReturn().addAll(m_server.getBooksByType(req.getType()));
        return rsp;
    }

    public GetTypesResponse getTypes(GetTypes req) {
        GetTypesResponse rsp = new GetTypesResponse();
        rsp.getGetTypesReturn().addAll(m_server.getTypes());
        return rsp;
    }
}


“Java Web Services: Axis2 Data Binding” 并没有展示针对不同数据绑定的服务器接口代码,但是如果您比较 清单 3 和从上文下载的代码,就会发现清单 3 非常接近于 ADB 和 JiBX 封装器例子,同样,惟一的区别在于使用了 Java 5 的类型类别而没有使用数组。

JAXB 数据模型类

清单 4 展示了通过运行 WSDL2Java 生成的 JAXB 数据模型类(生成的大多数注释已被删除,只留下少量注释作为例子)。生成的数据模型类对于客户机和服务器都是相同的,即使是由项目构建单独创建的。显示的 类用于 清单 2 的客户机代码和 清单 3 的服务器代码中的 getBook 调用。每个类定义上的注释(用粗体显示)和大部分字段定义提供了配置信息,供 JAXB 用于控制对象与 XML 的转换。

清单 4. JAXB 数据模型类

Java代码
  1. @XmlAccessorType (XmlAccessType.FIELD)  
  2. @XmlType (name =  "" , propOrder = {  
  3.     "isbn"   
  4. })  
  5. @XmlRootElement (name =  "getBook" )  
  6. public   class  GetBook {  
  7.   
  8.     @XmlElement (required =  true )  
  9.     protected  String isbn;  
  10.   
  11.     /**  
  12.      * Gets the value of the isbn property.  
  13.      *   
  14.      * @return  
  15.      *     possible object is  
  16.      *     {@link String }  
  17.      *       
  18.      */   
  19.     public  String getIsbn() {  
  20.         return  isbn;  
  21.     }  
  22.   
  23.     /**  
  24.      * Sets the value of the isbn property.  
  25.      *   
  26.      * @param value  
  27.      *     allowed object is  
  28.      *     {@link String }  
  29.      *       
  30.      */   
  31.     public   void  setIsbn(String value) {  
  32.         this .isbn = value;  
  33.     }  
  34. }  
  35.   
  36. @XmlAccessorType (XmlAccessType.FIELD)  
  37. @XmlType (name =  "BookInformation" , propOrder = {  
  38.     "author" ,  
  39.     "title"   
  40. })  
  41. public   class  BookInformation {  
  42.   
  43.     protected  List<String> author;  
  44.     @XmlElement (required =  true )  
  45.     protected  String title;  
  46.     @XmlAttribute (required =  true )  
  47.     protected  String type;  
  48.     @XmlAttribute (required =  true )  
  49.     protected  String isbn;  
  50.   
  51.     public  List<String> getAuthor() {  
  52.         if  (author ==  null ) {  
  53.             author = new  ArrayList<String>();  
  54.         }  
  55.         return   this .author;  
  56.     }  
  57.   
  58.     public  String getTitle() {  
  59.         return  title;  
  60.     }  
  61.   
  62.     public   void  setTitle(String value) {  
  63.         this .title = value;  
  64.     }  
  65.   
  66.     public  String getType() {  
  67.         return  type;  
  68.     }  
  69.   
  70.     public   void  setType(String value) {  
  71.         this .type = value;  
  72.     }  
  73.       
  74.     public  String getIsbn() {  
  75.         return  isbn;  
  76.     }  
  77.   
  78.     public   void  setIsbn(String value) {  
  79.         this .isbn = value;  
  80.     }  
  81. }  
  82.   
  83. @XmlAccessorType (XmlAccessType.FIELD)  
  84. @XmlType (name =  "" , propOrder = {  
  85.     "getBookReturn"   
  86. })  
  87. @XmlRootElement (name =  "getBookResponse" )  
  88. public   class  GetBookResponse {  
  89.   
  90.     protected  BookInformation getBookReturn;  
  91.   
  92.     public  BookInformation getGetBookReturn() {  
  93.         return  getBookReturn;  
  94.     }  
  95.   
  96.     public   void  setGetBookReturn(BookInformation value) {  
  97.         this .getBookReturn = value;  
  98.     }  
  99. }  
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "isbn"
})
@XmlRootElement(name = "getBook")
public class GetBook {

    @XmlElement(required = true)
    protected String isbn;

    /**
     * Gets the value of the isbn property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getIsbn() {
        return isbn;
    }

    /**
     * Sets the value of the isbn property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setIsbn(String value) {
        this.isbn = value;
    }
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BookInformation", propOrder = {
    "author",
    "title"
})
public class BookInformation {

    protected List<String> author;
    @XmlElement(required = true)
    protected String title;
    @XmlAttribute(required = true)
    protected String type;
    @XmlAttribute(required = true)
    protected String isbn;

    public List<String> getAuthor() {
        if (author == null) {
            author = new ArrayList<String>();
        }
        return this.author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String value) {
        this.title = value;
    }

    public String getType() {
        return type;
    }

    public void setType(String value) {
        this.type = value;
    }
    
    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String value) {
        this.isbn = value;
    }
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "getBookReturn"
})
@XmlRootElement(name = "getBookResponse")
public class GetBookResponse {

    protected BookInformation getBookReturn;

    public BookInformation getGetBookReturn() {
        return getBookReturn;
    }

    public void setGetBookReturn(BookInformation value) {
        this.getBookReturn = value;
    }
}


@XmlAccessorType 注释在包或类级别使用,用于控制从类中访问值的方式 — 包括访问所有字段、访问所有具有 get/set 访问方法的属性、只访问公开字段和属性,或仅根据某个注释的指定进行访问。@XmlType 注释在匹配某个模式类型的类或 enum 定义中使用,以向 JAXB 提供模式类型的名称和名称空间(如果有的话)、类型表示中的值的顺序,以及如何使用一个工厂方法构建类的实例(可选)。@XmlRootElement 注释在匹配全局元素定义的类或 enum 定义中使用,用于提供全局元素的名称和名称空间。@XmlElement 和 @XmlAttribute 注释在值中使用(以字段或 JavaBean 属性方法的形式),提供元素或属性名和其他特征)。

JAXB 使用的所有注释都位于 javax.xml.bind.annotation 包中,除了这个简单示例生成的代码中使用的注释外,还包括许多其他注释。JAXB 支持从模式中生成代码(本例就属于此例),也支持从代码中生成。某些注释和选项(比如那些处理对象工厂和串行器/并行器方法的注释和选项)只能用于从代码 中生成的情况。

Axis2 中的 JAXB 问题

WSDL2Java 调用 JAXB 参考实现中附带的 XJC 绑定编译器来生成数据模型代码,因此在大多数方面数据模型代码的生成是独立于 Axis2 的。如果直接在 Web 服务使用的模式上面运行 JAXB XJC 绑定编译器,您将生成相同的数据模型。不幸的是,WSDL2Java 和 XJC 之间的阻抗匹配并不总是正确的,这就会导致一些问题。

其中一个问题与在 WSDL 文档中构建模式的方式有关。库服务的初始 WSDL 使用单个文档,该文档合并了两个独立的模式,一个用于 WSDL 消息元素,另一个用于应用程序数据(图书和类型信息)。如 WSDL 允许的那样,消息元素模式通过名称空间引用导入了应用程序数据模式。这个包含嵌入模式的 WSDL 可以很好地与使用 ADB 或 JiBX 数据绑定的 WSDL2Java 工作,但是对于 JAXB,它将在模式处理期间引发一个异常抛出。将应用程序数据模式分离到一个单独的文件并在模式导入时指定文件名称,这将允许 WSDL2Java 使用 JAXB 绑定正确地处理模式。

另一个问题是,XJC 提供了大量代码生成选项以及许多定制来控制针对某一特定模式组件的代码生成细节 — 但是 WSDL2Java 没有提供任何方法来将这些选项或定制传递给 XJC,因此代码生成将始终按照默认设置运行。如果需要使用任何代码生成选项或定制,可能需要单独运行 XJC 和 WSDL2Java。不幸的是,无法在 WSDL2Java 代码生成中使用单独生成的 JAXB 数据模型。如果需要使用定制的 JAXB 数据模型,最佳办法可能就是运行 WSDL2Java 以生成其自己的 JAXB 代码模型,然后再换入您单独生成的数据模型类,并根据需要手动修改代码来将所有内容联合到一起。或者,可以像下一小节介绍的那样使用 JAX-WS,这将使您完全跳过 WSDL2Java,但是存在一些明显的限制。

在 Axis2 中使用 JAX-WS

虽然可以将 JAXB 作为 Axis2 中的另一种数据绑定替代选择,但是它与 JAX-WS 之间的区别更加显著。JAX-WS 是一种截然不同的 Web 服务定义方法,它全面取代了标准的 Axis2 服务器端和客户端配置。您使用 JAX-WS 参考实现(必须从 Axis2 中单独下载;参见 参考资料)中附带的 WsImport 工具从 WSDL 中生成 JAX-WS 代码,而不是使用 WSDL2Java。甚至部署机制也不同于 Axis2 中通常使用的 AAR 文件方法。

代码 下载 部分只提供了早先使用的同一样例应用程序的不同版本,这个版本进行了修改,用于演示 JAX-WS 在 Axis2 中的使用。代码位于下载中的 jaxws 目录中,并且它带有自己的 WSDL、build.properties 和 build.xml。这个 JAX-WS 版本的 WSDL 基本上与用于 JAXB 的 WSDL 相同,如 清单 1 所示。该 WSDL 的主要区别在于它对应用程序代码使用了内嵌的模式,而这对于使用 JAXB 数据绑定的 WSDL2Java 来说是不可行的。

当使用 JAX-WS 的 WsImport 工具从 WSDL 创建代码时,将获得与使用 WSDL2Java 实现 JAXB 代码生成时相同的 JAXB 数据模型和封装器类。不同之处在于链接(linkage)代码,对于 JAX-WS,链接代码包含一个生成的服务接口和一个客户端服务构建器类。接口类,如 清单 5(稍微进行了重新格式化,并且只保留了一个方法注释)所示,定义了与 WSDL 中的操作匹配的方法。客户机代码和服务器代码都使用这个接口。接口中的大量注释提供了所有必需配置信息,帮助 JAX-WS 将服务接口与该服务的操作的接口方法关联起来。

清单 5. JAX-WS 生成的服务接口

Java代码
  1. @WebService (name =  "Library" , targetNamespace =  "http://ws.sosnoski.com/library/wsdl" )  
  2. @XmlSeeAlso ({  
  3.     ObjectFactory.class   
  4. })  
  5. public   interface  Library  
  6. {  
  7.     /**  
  8.      *   
  9.      * @param isbn  
  10.      * @return  
  11.      *     returns com.sosnoski.ws.library.jaxws.BookInformation  
  12.      */   
  13.     @WebMethod (action =  "urn:getBook" )  
  14.     @WebResult (name =  "getBookReturn" ,  
  15.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" )  
  16.     @RequestWrapper (localName =  "getBook" ,  
  17.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  18.         className = "com.sosnoski.ws.library.jaxws.GetBook" )  
  19.     @ResponseWrapper (localName =  "getBookResponse" ,  
  20.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  21.         className = "com.sosnoski.ws.library.jaxws.GetBookResponse" )  
  22.     public  BookInformation getBook(  
  23.         @WebParam (name =  "isbn" , targetNamespace =  "http://ws.sosnoski.com/library/wsdl" )  
  24.         String isbn);  
  25.   
  26.     @WebMethod (action =  "urn:getBooksByType" )  
  27.     @WebResult (name =  "getBooksByTypeReturn" ,  
  28.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" )  
  29.     @RequestWrapper (localName =  "getBooksByType" ,  
  30.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  31.         className = "com.sosnoski.ws.library.jaxws.GetBooksByType" )  
  32.     @ResponseWrapper (localName =  "getBooksByTypeResponse" ,  
  33.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  34.         className = "com.sosnoski.ws.library.jaxws.GetBooksByTypeResponse" )  
  35.     public  List<BookInformation> getBooksByType(  
  36.         @WebParam (name =  "type" , targetNamespace =  "http://ws.sosnoski.com/library/wsdl" )  
  37.         String type);  
  38.   
  39.     @WebMethod (action =  "urn:getTypes" )  
  40.     @WebResult (name =  "getTypesReturn" ,  
  41.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" )  
  42.     @RequestWrapper (localName =  "getTypes" ,  
  43.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  44.         className = "com.sosnoski.ws.library.jaxws.GetTypes" )  
  45.     @ResponseWrapper (localName =  "getTypesResponse" ,  
  46.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  47.         className = "com.sosnoski.ws.library.jaxws.GetTypesResponse" )  
  48.     public  List<TypeInformation> getTypes();  
  49.   
  50.     @WebMethod (action =  "urn:addBook" )  
  51.     @WebResult (name =  "addBookReturn" ,  
  52.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" )  
  53.     @RequestWrapper (localName =  "addBook" ,  
  54.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  55.         className = "com.sosnoski.ws.library.jaxws.AddBook" )  
  56.     @ResponseWrapper (localName =  "addBookResponse" ,  
  57.         targetNamespace = "http://ws.sosnoski.com/library/wsdl" ,  
  58.         className = "com.sosnoski.ws.library.jaxws.AddBookResponse" )  
  59.     public   boolean  addBook(  
  60.         @WebParam (name =  "type" , targetNamespace =  "http://ws.sosnoski.com/library/wsdl" )  
  61.         String type,  
  62.         @WebParam (name =  "isbn" , targetNamespace =  "http://ws.sosnoski.com/library/wsdl" )  
  63.         String isbn,  
  64.         @WebParam (name =  "author" ,  
  65.             targetNamespace = "http://ws.sosnoski.com/library/wsdl" )  
  66.         List<String> author,  
  67.         @WebParam (name =  "title" , targetNamespace =  "http://ws.sosnoski.com/library/wsdl" )  
  68.         String title)  
  69.         throws  AddDuplicateFault  
  70.     ;  
  71. }  
@WebService(name = "Library", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface Library
{
    /**
     * 
     * @param isbn
     * @return
     *     returns com.sosnoski.ws.library.jaxws.BookInformation
     */
    @WebMethod(action = "urn:getBook")
    @WebResult(name = "getBookReturn",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl")
    @RequestWrapper(localName = "getBook",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl",
        className = "com.sosnoski.ws.library.jaxws.GetBook")
    @ResponseWrapper(localName = "getBookResponse",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl",
        className = "com.sosnoski.ws.library.jaxws.GetBookResponse")
    public BookInformation getBook(
        @WebParam(name = "isbn", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
        String isbn);

    @WebMethod(action = "urn:getBooksByType")
    @WebResult(name = "getBooksByTypeReturn",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl")
    @RequestWrapper(localName = "getBooksByType",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl",
        className = "com.sosnoski.ws.library.jaxws.GetBooksByType")
    @ResponseWrapper(localName = "getBooksByTypeResponse",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl",
        className = "com.sosnoski.ws.library.jaxws.GetBooksByTypeResponse")
    public List<BookInformation> getBooksByType(
        @WebParam(name = "type", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
        String type);

    @WebMethod(action = "urn:getTypes")
    @WebResult(name = "getTypesReturn",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl")
    @RequestWrapper(localName = "getTypes",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl",
        className = "com.sosnoski.ws.library.jaxws.GetTypes")
    @ResponseWrapper(localName = "getTypesResponse",
        targetNamespace = "http://ws.sosnoski.com/library/wsdl",
        className = "com.sosnoski.ws.library.jaxws.GetTypesResponse")
    public List<TypeInformation> getTypes();

    @WebMethod(action = "urn:addBook")
    @WebResult(name = "addBookReturn",
        targetNamespace = "http://ws.sosnoski.com/librar
  

猜你喜欢

转载自calvinliu.iteye.com/blog/769976