Code generation for JiBX data binding converts operations defined by a Web service to method calls. In the most general case of document/literal (doc/lit) Web services the generated methods each take a single parameter object and return a single result object. This type of interface can be painful for developers because it adds both a layer of indirection and potentially a large number of extra classes (one input and one output class for each generated method).
Fortunately, there's an alternative way of generating methods that gives a much more usable API for many Web services. This alternative is called unwrapping, and the service definitions that it applies to are called wrapped definitions. The key difference that qualifies a service definition as wrapped is the structure of the input and output elements used for operations.
Here's a sample wrapped WSDL (partial) by way of an example:
<wsdl:definitions targetNamespace="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/types" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="getBook"> <complexType> <sequence> <element name="isbn" type="string"/> </sequence> </complexType> </element> <element name="getBookResponse"> <complexType> <sequence> <element name="book" minOccurs="0" type="tns:BookInformation"/> </sequence> </complexType> </element> <element name="addBook"> <complexType> <sequence> <element name="type" type="string"/> <element name="isbn" type="string"/> <element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/> <element name="title" type="string"/> </sequence> </complexType> </element> <element name="addBookResponse"> <complexType> <sequence> <element name="success" type="boolean"/> </sequence> </complexType> </element> <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:message name="addBookRequest"> <wsdl:part element="wns:addBook" name="parameters"/> </wsdl:message> <wsdl:message name="addBookResponse"> <wsdl:part element="wns:addBookResponse" 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:operation name="addBook"> <wsdl:input message="wns:addBookRequest" name="addBookRequest"/> <wsdl:output message="wns:addBookResponse" name="addBookResponse"/> </wsdl:operation> </wsdl:portType> ... </wsdl:definitions>
This WSDL defines a service with just two operations: getBook and addBook. The getBook operation takes a getBook element as input, and returns a getBookResponse element as output, while addBook takes an addBook element as input and returns an addBookResponse as output. Each of these input and output elements in turn consists of a sequence of child elements, with some of the child elements defined directly using standard schema types and others referencing user-defined schema types.
As I said up front, this WSDL qualifies for unwrapped handling using JiBX. Here's the body of the client interface generated when using unwrapping (the -uw option for WSDL2Java):
public interface LibraryJibxUnwrapped { /** * Auto generated method signatures * @param type* @param isbn* @param author* @param title */ public boolean addBook( java.lang.String type,java.lang.String isbn,java.lang.String[] author,java.lang.String title) throws java.rmi.RemoteException ; /** * Auto generated method signatures * @param isbn */ public com.sosnoski.ws.library.jibx.beans.Book getBook( java.lang.String isbn) throws java.rmi.RemoteException ; // }
You can see that the JiBX code generation converted the operations into simple method call interfaces without introducing any extraneous objects (see JiBX Document/Literal Example for the interface generated when unwrapping is not used). The server-side interface is the same.
The key points that allow unwrapped handling with JiBX are:
You also need to supply an appropriate JiBX binding definition (using the -Ebindingfile {file} parameter for WSDL2Java - see JiBX Codegen Integration - WSDL2Java usage for more details). This must define abstract mappings for the complexTypes referenced by child elements of the inputs and outputs, with a type-name attribute matching the schema complexType name. If the child elements reference schema simpleType definitions the binding must also define a formats for each simpleType, with a label attribute matching the schema simpleType name. The binding definition must also specify the force-classes='true' attribute on the binding element.
For example, here's a binding definition that matches the above WSDL:
<binding force-classes="true" xmlns:tns="http://ws.sosnoski.com/library/types"> <namespace uri="http://ws.sosnoski.com/library/types" default="elements"/> <mapping abstract="true" class="com.sosnoski.ws.library.jibx.beans.Book" type-name="tns:BookInformation"> <value name="type" style="attribute" field="m_type"/> <value name="isbn" style="attribute" field="m_isbn"/> <collection field="m_authors"> <value name="author"/> </collection> <value name="title" field="m_title"/> </mapping> </binding>
And here's the actual
com.sosnoski.ws.library.jibx.beans.Book
class:
package com.sosnoski.ws.library.jibx.beans; public class Book { private String m_type; private String m_isbn; private String m_title; private String[] m_authors; public Book() {} public String getType() { return m_type; } public String getIsbn() { return m_isbn; } public String getTitle() { return m_title; } public String[] getAuthors() { return m_authors; } }
The JiBX code generation for Axis2 currently requires that
classes coresponding to unwrapped child elements (such as
com.sosnoski.ws.library.jibx.beans.Book
, in this case)
provide public default (no-argument) constructors.
JiBX handling allows the child elements of both inputs and outputs to be optional (with nillable='true', minOccurs='0', or both), providing the binding converts these child elements to object types rather than primitive types. It also allows repeated child elements (with minOccurs='unbounded', or any value of minOccurs greater than one), representing the repeated elements as arrays of the corresponding object or primitive types.