Web Services Custom Data Binding, Part 1: How to choose a custom mapping technology for Web services

In most scenarios, the mapping from XML schema to Java™, as defined by JAX-RPC, yields a suitable set of Java beans for handling your Web services data. However, there are cases when you may prefer an alternate mapping, or when there just isn't a well-defined mapping for your particular schema construct (xsd:choice is a common example). For these cases, IBM® WebSphere® V6 has introduced a new feature called Custom Data Binding that allows you to integrate alternate data binding technologies like JAX-B, EMF/SDO and XML beans, as well to define your own XML schema to Java mappings. This article provides an overview of the technology and how you can get started integrating it into your application.

Nicholas Gallardo (nlgallar@us.ibm.com), Staff Software Engineer, IBM

Nick Gallardo works as a software engineer on the IBM WebSphere platform, focusing on various aspects of the Web services support. His previous work in IBM includes other assignments within the WebSphere and Tivoli platforms. Nick came to IBM in 2001 after working in development in two different technology start-ups in Austin, Texas.



Greg Truty (gtruty@us.ibm.com), Senior Technical Staff Member, IBM

Greg Truty is an IBM WebSphere Application Server Web services architect. He has been doing distributed computing for over 10 years, and has been involved in Web services for over 5 years. He has participated in implementing the Web services for J2EE (JSR 109) and JAX-RPC (JSR 101) specifications for WebSphere. He was involved in pushing JAX-RPC 1.0 out to Apache Axis. You can contact Greg at gtruty@us.ibm.com.



25 January 2006

Also available in Russian

Introduction

Because of JAX-RPC's limited support for certain XML schema constructs, it's not unusual for a JAX-RPC-based WSDL-to-Java generation tool to leave you with a set of Java beans that don't really behave like you were expecting. This is most commonly evidenced by getting a javax.xml.soap.SOAPElement when you expected to have a constructed Java type representing your schema type. Creating and populating these SOAPElements directly instead of populating normal Java beans can become a little unwieldy and can quickly clutter an application.

Alternately, you may already be using a particular XML binding technology in your application, which you now want to expose as a Web service. In this case, you probably don't want to rewrite the application to handle the overlap between your existing beans and the new ones JAX-RPC may require.

Using examples, we'll show you how WebSphere's new Custom Data Binding feature works, and how it can help address these scenarios by allowing you to use your own mapping technology for your Web services data. This feature was first introduced in WebSphere Application Server Base and Network Deployment Version 6.

Serialization and deserialization in WebSphere

Before we dive down into the specifics of Custom Data Binding, an understanding of the current serialization and deserialization environment in WebSphere will help you understand how it can be extended for custom serialization.

Type mapping vs. element mapping

The current Web services runtime (introduced in WebSphere V5.0.2) supports the JAX-RPC programming model, which is based on the notion of a type-mapping registry. That is, each type that exists in the WSDL or XSD file will have a special serializer or deserializer created for it that knows how to handle those types. This notion of type-mapping is a key point to remember when developing your Custom Data Binding application. This is different from an element-centric mapping, in which the Java types are generated based on a particular root element definition within the WSDL. In a type-centric mapping, the user view of the data is based on the types that exist within the XSD associated with the particular WSDL.

Mapping WSDL to Java

Let's look at an example. Listing 1 shows an XSD snippet pulled from a associated WSDL file, with two elements that correspond to the input and output of an operation. The request takes an input object of type OpType, while the response returns a simple String. JAX-RPC would map the complex type OpType to a Java object called OpType that contains two attributes, c1 and c2, each of type String..

Listing 1. Sample XSD from WSDL
<xsd:element name="Op1Response" type="xsd:string" />

<xsd:element name="Op1Request" type="tns:OpType" />

<xsd:complexType name="OpType">
    <xsd:sequence>
        <xsd:element name="c1" type="xsd:string"/>
        <xsd:element name="c2" type="xsd:string"/>
    </xsd:sequence>
</xsd:complexType>

An example of this class is shown seen in Listing 2. If these elements were more complex types, further nesting would be created

Listing 2. Java bean mapping for sample XSD.
public class OpType {
	
	private String c1;
	private String c2;
	
	public String getC1() {
		return c1;
	}
	
	public void setC1(String val) {
		c1 = val;
	}
	
	public String getC2() {
		return c2;
	}
	
	public void setC2(String val) {
		c2 = val;
	}

}

Another common example uses the notion of a wrapped operation, which has become widely accepted within the industry despite the fact that there is no formal definition for the pattern. This pattern defines an element/complexType mapping whose element name is the same as the operation name. The child elements in the complex type represent the parameters of the operation.

Understanding WSDL patterns

There are four patterns you can use when constructing a WSDL: Document/Literal, Document/Literal Wrapped, RPC/Literal and RPC/Encoded. For a comparison these patterns, check out the article by Russell Butek in the Resources section, entitled Which style of WSDL should I use?

Looking at a snippet of the sample WSDL file in Listing 3, you'll see that there are two elements defined, followed by two parts pointing to those elements. The first element is an operation wrapper, which takes two arguments (one of type xsd:int and one of type xsd:string). The second is a response element, which holds one element (of type xsd:string).

These elements are defined as the input and output parts of the WSDL message (operation1Request and operation1Response).

Listing 3. Sample wrapped WSDL snippet
<element name="operation1">
    <complexType>
        <sequence>
            <element name="arg_0_0" type="xsd:int"/>
            <element name="arg_1_0" nillable="true" type="xsd:string"/>
        </sequence>
    </complexType>
</element>

<element name="operation1Response">
    <complexType>
        <sequence>
            <element name="operation1Return" nillable="true" type="xsd:string"/>
        </sequence>
    </complexType>
</element>

<wsdl:message name="operation1Request">
    <wsdl:part element="impl:operation1" name="parameters"/>
</wsdl:message>

<wsdl:message name="operation1Response">
    <wsdl:part element="impl:operation1Response" name="parameters"/>
</wsdl:message>

<wsdl:portType name="MyPortType">
    <wsdl:operation name="operation1">
        <wsdl:input message="impl:operation1Request" 
                name="operation1Request"/>
        <wsdl:output message="impl:operation1Response" 
                name="operation1Response"/>
    </wsdl:operation>
</wsdl:portType>

In JAX-RPC, these parameters are deserialized into normal Java objects and primitive data types. Using the WSDL2Java tool provided by WebSphere, the generated JAX-RPC service interface for this WSDL would look like the one shown below in Listing 4. Note that, in this example, the runtime has unwrapped the operational wrapper to give it a more RPC-like flavor.

Listing 4. Sample JAX-RPC Service Endpoint Interface
public interface MyPortType extends java.rmi.Remote {
    public java.lang.String operation1(int a, java.lang.String b)
        throws java.rmi.RemoteException;
}

Using the -noWrappedOperations flag on the WSDL2Java tool, the WSDL would not be treated as having a wrapped operation, and the contents of the element will not be unwrapped before returning them to the bean. In this scenario, beans would have been generated for all of the complex types, and instead of accepting the two individual params (int and String), the interface will have to accept the entire operation wrapper element. When the Service Endpoint Interface (SEI) is generated from the portType, it will look like the one in Listing 5. This example becomes key when dealing with trying to map full XML documents, which we'll get to later).

Listing 5. Sample JAX-RPC Service Endpoint Interface
public interface MyPortType extends java.rmi.Remote {
    public a.b.Operation1Response operation1(a.b.Operation1 parameters)
        throws java.rmi.RemoteException;
}

Making Your Service Generic

Now that you have a high-level understanding of how types are mapped and serialized within WebSphere, let's take a look at what you need to do to your Web service to make use of Custom Data Binding. This section discusses how the data model (your custom Java beans) for a particular Web service can be separated from the invocation model (the interfaces that you're invoking against).

To be able to achieve our goal of plugging in alternate mapping technologies, we first need the ability to work with the data model separate from the invocation model. We need the parameter(s) to the Web service to be in a more generic form, so that we can easily go to and from the generic representation to the custom objects. To do this, we'll use the -noDataBinding option on WebSphere's WSDL2Java tool.

In SAAJ (or the SOAP with Attachments API for Java) Version 1.2, the SOAPElement API is an extension of the DOM APIs. This was not available in the previous version, SAAJ 1.1, and helps by allowing manipulation of the data through well-known APIs. WebSphere V6 supports SAAJ 1.2, while SAAJ 1.1 support is included in WebSphere Versions 5.0.2 to 5.1.x.

When the -noDataBinding flag is specified, WSDL2Java refrains from binding any of the schema artifacts to their normal Java bean representation. Instead, everything is mapped to an SAAJ SOAPElement. The SOAPElement API is used in JAX-RPC as a generic form to encapsulate the schema types and nuances that it does not have a mapping for (for example xsd:choice).

If you take a look at Listing 6, you'll see the generated JAX-RPC interface for this scenario. This interface is based on the sample WSDL in Listing 3. As mentioned, all of the input and output types are mapped to SOAPElement trees containing the XML text.

Listing 6. Sample JAX-RPC interface with no data binding
public interface MyPortType extends java.rmi.Remote {
    public javax.xml.soap.SOAPElement operation1(javax.xml.soap.SOAPElement parameters)
        throws java.rmi.RemoteException;
}

It's important to remember that this is a WebSphere-specific feature, and as such, there is not a specification or standard that defines what the WSDL-to-Java mapping would be for this No Data Binding format. However, the pattern used by the tool is that the signature for methods generated in the JAX-RPC interface contains a SOAPElement for each part within the WSDL. In other words, the number of input parameters on the method corresponds to the number of <wsdl:part/>s within <wsdl:message>. Looking back at our WSDL defined in Listing 3, you'll see that there is a single part parameters for the message operation1Request that represents the request. Thus, we see only one SOAPElement representing the entire request payload.

If you're using the Rational® Application Developer tool to develop your Web services applications, the option for disabling data binding on the generated interfaces can be a little tricky to find. To find it, select Preferences => Web Services => Code Generation => IBM WebSphere Runtime, then select Disable data binding and use SOAPElement.

Figure 1. Disable data binding in Rational Application Developer
Disable data binding in Rational Application Developer

Additional helpful APIs

While it's possible to implement a Web service that uses the No Data Binding pattern with only the offical SAAJ 1.2 SOAPElement APIs, IBM has introduced some additional methods on their SOAPElement implementation in order to support these extensions. These are defined in a public, IBM-specific SOAPElement interface in com.ibm.websphere.webservices.soap.IBMSOAPElement.

Specifically, there are two methods on this interface that are useful when writing a no data binding application: toXMLString(boolean) and toInputSource(boolean).

  • toXMLString(boolean) allows you to get the contents of the SOAPElement as an XML string. The string returned is be the exact contents of the current SOAPElement and its descendants. This string can then be parsed in whatever manner you choose and deserialized into your chosen object form. In some cases, the contents of the SOAP Body may rely on namespace declarations that occur at a higher level in the SOAP Envelope. In these cases, if the boolean parameter is set to true, the returned string will include the SOAPElement data along with all namespace declarations from ancestor elements.
  • toInputSource(boolean) allows you to get the contents of the SOAPElement as an InputSource. This InputSource can be fed into other runtimes or parsers in order to deserialize the data into other object types. As with the toXMLString, the boolean parameter determines whether all namespace declarations from the ancestors are included.
Listing 7. The IBMSOAPElement interface
package com.ibm.websphere.webservices.soap;

public interface IBMSOAPElement extends SOAPElement {
    public String toXMLString (boolean includeNSDecls);
    
    public InputSource toInputSource (boolean includeNSDecls) 
        throws SAXException;

    ...
}

The API described in Listing 7 is useful only when you have an existing SOAPElement and need to get the data out in an easy manner. That means that you would only use the APIs when a SOAPElement comes into your system (an inbound request to a server or an inbound response to a client). However, there are also APIs that have been created to assist with creating new SOAPElements. You can use these in an outbound scenario in which you have an object containing some form of XML data and would like to create a SOAPElement out of it. IBM has provided an optimized solution for this scenario through the com.ibm.websphere.webservices.soap.IBMSOAPElementFactory. This interface allows for the creation of SOAPElements from both an InputSource and an XML String.

Listing 8. The IBMSOAPElementFactory interface
package com.ibm.websphere.webservices.soap;

import javax.xml.soap.*;
import org.xml.sax.InputSource;

public interface IBMSOAPFactory {
    public SOAPElement createElementFromXMLString(
            String xmlString) throws SOAPException;
    public SOAPElement createElementFromInputSource(
            InputSource inputSource) throws SOAPException;
}

Invariably, the question comes up: why did IBM create these APIs and why should I use them? These APIs are provided as tools to make working with SOAPElements easier, but are by no means required to implement what is needed for this scenario. Using them does simplify the code a bit for the cases where you'll need to handle the SOAPElements themselves instead of working with your data objects.


How custom data binding works

Now that you've been introduced to the enhanced SOAPElement support and understand the concept of No Data Binding, you have all the tools needed to leverage the new Custom Serialization feature within WebSphere.

What is custom data binding?

Looking at JAX-RPC, you'lll see that the WSDL/XML Schema to Java mappings are somewhat limited. For some of the more complicated schema concepts, JAX-RPC choses to map these (for example, xsd:anyAttribute, xsd:choice, and so on) to a SOAPElement. If we look forward to JAX-WS 2.0, the next evolution of the J2EE Web services programming model, you'll note that instead of defining its own mappings, it chooses to use the JAX-B 2.0 specification for its data binding. JAX-B is a more complete mapping of XML schema than JAX-RPC provides, but they are distinct. Unfortunately, it was not possible for JAX-RPC to use JAX-B 2.0 as it's data binding mechanism since the specification was not yet complete. In many cases though, you'll want to map your Web services data using JAX-B or another binding technology that makes more sense to your and your application. Or, perhaps you've already got a set of Java beans that you're using and you'd like to maintain that mapping over a different one chosen by JAX-RPC.

Using some of the concepts and features introduced above, it's possible to handle this by working with the raw SOAPElements as the input and output parameters and doing the conversions yourself. However, this means that the SOAPElement will now appear in your Service Endpoint Interface (or as properties inside of an object) and anyone that you provide that to will have to understand how to deal with SOAPElement as well. Custom Data Binding allows you to hide this logic below the interface level and present a more application-centric API.

Specifically, WebSphere allows this by introducing a Custom Binder interface, which allows a mapping from an XML schema type to a Java type (and vice versa). A Custom Binder has methods that are capable of handling specific XML schema types, turning them into designated Java objects. Conversely, the Custom Binder also handles serializing your custom Java object into its correct XML representation.

Let's say, for example, that you've generated your SEI from the WSDL in Listing 9 that contains an xsd:choice in one of the complex types. For the purposes of this example, we'll call the interface InventorySearch. Without the use of a Custom Binder, the generated interface would look like the one in Listing 10, with a SOAPElement as the return type. However, if we have a Custom Binder in place for the schema type in question, the generated interface would look more like what you expect (as shown in Listing 11), and would expose the appropriate data types as the input and response type.

Listing 9. A sample WSDL with an unmappable complex type
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://mycorp.com" 
       xmlns:impl="http://mycorp.com" 
       xmlns:intf="http://mycorp.com" 
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
       xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
       xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd" 
       xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <wsdl:types>
  <schema targetNamespace="http://mycorp.com" xmlns="http://www.w3.org/2001/XMLSchema">
   <element name="findItemResponse">
    <complexType>
     <sequence>
      <element name="findItemReturn" nillable="true" type="impl:InventoryItem"/>
     </sequence>
    </complexType>
   </element>
   <element name="findItem">
    <complexType>
     <sequence>
      <element name="arg_0_0" type="xsd:int"/>
     </sequence>
    </complexType>
   </element>
   <complexType name="InventoryItem">
    <sequence>
     <element name="productId" type="xsd:int"/>
     <element name="productName" nillable="true" type="xsd:string"/>
      <xsd:choice>
       <element name="reorderNeeded" type="xsd:boolean"/>
       <element name="stockCount" type="xsd:int"/>
      </xsd:choice>
    </sequence>
   </complexType>
  </schema>
 </wsdl:types>

   <wsdl:message name="findItemResponse">

      <wsdl:part element="impl:findItemResponse" name="parameters"/>

   </wsdl:message>

   <wsdl:message name="findItemRequest">

      <wsdl:part element="impl:findItem" name="parameters"/>

   </wsdl:message>

   <wsdl:portType name="InventorySearch">

      <wsdl:operation name="findItem">

         <wsdl:input message="impl:findItemRequest" name="findItemRequest"/>

         <wsdl:output message="impl:findItemResponse" name="findItemResponse"/>

      </wsdl:operation>

   </wsdl:portType>

   <wsdl:binding name="InventorySearchSoapBinding" type="impl:InventorySearch">

      <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

      <wsdl:operation name="findItem">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="findItemRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="findItemResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

   </wsdl:binding>

   <wsdl:service name="InventorySearchService">

      <wsdl:port binding="impl:InventorySearchSoapBinding" name="InventorySearch">

         <wsdlsoap:address location="file:undefined_location"/>

      </wsdl:port>

   </wsdl:service>

</wsdl:definitions>

Listings 10 and 11 shows a Service Endpoit Interface without and with custom data binding.

Listing 10. A Service Endpoint Interface without custom data binding
import javax.xml.soap.SOAPElement;

public interface InventorySearch extends java.rmi.Remote {
    public SOAPElement findItem(int productId) 
        throws java.rmi.RemoteException;
}
Listing 11. A Service Endpoint Interface with custom data binding
import com.mycorp.InventoryItem;

public interface InventorySearch extends java.rmi.Remote {
    public InventoryItem findItem(int productId)
        throws java.rmi.RemoteException;
}

Where to use custom binders

The WebSphere runtime and tooling uses of the custom binders at development time as well as runtime. At development time, it searches for available custom binders, and queries each of them to find the schema type and Java type they support. This information is used to update the type mapping registries, and when it is time to produce interfaces or stubs, will generate code that uses the correctly mapped types instead of a SOAPElement or some other type.

Similarly, the runtime locates the custom binders and uses whatever binders it needs to perform its function. It tries to find all instances of /META-INF/services/CustomBindingProvider.xml and uses that information to set up its type mapping registries and to get each of the custom binders ready to serialize and deserialize.

In the WebSphere runtime, it searches the classpath for the available custom binders. You can define your custom binders at varying levels of the classpath depending on the level of granularity you want. For instance, if you bundle your custom binder within your EJB jar or web application war file, the custom binder will be available only to that particular module. Or, you can make it more widely available by creating a shared library so that any module using that shared library can see it. Also, you can make it visible to all of WebSphere by placing it in the lib directory of your WebSphere installation.

Creating a custom binder and custom binding artifacts

A custom binder consists of two artifacts that you'll need to create. The first is an XML file, CustomBindingProvider.xml, that declares all the necessary information for the tooling and runtime to locate the binder. The second is an implementation of the binder class that is specified in the CustomBindingProvider.xml. This class handles the serialization and deserialization of objects by implementing a specific interface. We'll discuss the custom binder class at greater length later in this article.

Below you'll find a list of the different elements that are required in an instance of the CustomBindingProvider.xml. Each of these is required to be populated in your file, and must have a value in order for the custom binder to work correctly.

  • xmlQName: The XML named type that you are mapping from
  • javaName: The Java class name that you are mapping to
  • qnameScope: The scope of the type
  • binder: The Java class name of the custom binder to be used when this type is encountered

Once created, the CustomBindingProvider.xml is normally packaged along with the binder class(es) in the same jar file, and must be saved under the path /META-INF/services/CustomBindingProvider.xml. Listing 12 is an example instance of a CustomBindingProvider.xml based on the InventorySearch example we started above.

Listing 12. A sample CustomBindingProvider.xml file
<?xml version="1.0" encoding="UTF-8"?>
<provider xmlns="http://www.ibm.com/webservices/customdatabinding/2004/06" 
   xmlns:mycorp="http://mycorp.com">
   <mapping>
      <xmlQName>mycorp:IventoryItem</xmlQName>
      <javaName>com.mycorp.IventoryItem</javaName>
      <qnameScope>complexType</qnameScope>
      <binder>com.mycorp.InventoryItemBinder</binder>
   </mapping>
</provider>

In the example above, you can see that we've specified a custom binder that maps the mycorp:IventoryItem complex type that was defined in the schema and maps that on to the com.mycorp.InventoryItem Java type.

The custom binder class specified in the <binder/> element is a Java class that implements the interface com.ibm.wsspi.webservices.binding.CustomBinder required for custom binding. These methods provide information to the runtime as to what QNames and/or what Java types they map to, along w/the serialization and deserialization methods. The two methods are: serialize(Object, SOAPElement, CustomBindingContext) and deserialize(SOAPElement, CustomBindingContext). Once the custom binder is recognized by the runtime, it communicates with the runtime via the SOAPElement in the following ways:

  • For serialization, the binder's serialize method is invoked by the runtime and it receives a Java object and a SOAPElement. The Java object is the data to be serialized, and SOAPElement is the context element for the serialization. This SOAPElement represents the place in the SOAP Envelope where your data will go so that all you have to do is populate it.
  • Unlike the conventional serializer which writes out the raw data, the custom binder produces an intermediate form of SOAP message as a SOAPElement. The runtime takes care of writing the SOAPElement to the raw data. Obviously, it's easier to create the SOAPElement rather than the raw text because SAAJ APIs are available to help. Once the SOAPElement has been populated with the necessary data, it must be returned to the caller.
  • Similarly during deserialization, the runtime builds an appropriate javax.xml.soap.SOAPElement instance and passes it to the binder, which then deserializes it to a Java object. It's the responsibility of the custom binder to build and populate the correct Java object instance based on the SOAPElement that was passed in.

Listing 13 shows the CustomBinder interface.

Listing 13. The CustomBinder interface
public interface CustomBinder 	 {
    // the QName this binder targets
    public QName getQName():

    // QName scope for this binder
    public String getQNameScope();

    // the Java type name for unmarshalling
    public String getJavaName();	

    // serialize the Java object to SOAPElement
    public javax.xml.soap.SOAPElement serialize (Object bean,
            SOAPElement rootNode, CustomBindingContext context) 
        throws SOAPException;

    // deserialize the SOAPElement to Java object
    public Object deserialize (javax.xml.soap.SOAPElement source, 
            CustomBindingContext context)  
        throws SOAPException;
}

Listing 14 contains a skeleton of what a custom binder class would look like for our InventorySearch example.

Listing 14. A sample CustomBinder skeleton implementation
import com.ibm.wsspi.webservices.binding.CustomBinder;
import com.ibm.wsspi.webservices.binding.CustomBindingContext;

public class InventoryItemBinder implements CustomBinder {
    public QName getQName() {
        return new QName("http://mycorp.com", "InventoryItem");
    }

    public String getQNameScope() {
        return CustomBinder.QNAME_SCOPE_COMPLEXTYPE;
    }

    public String getJavaName() {
        return com.mycorp.InventoryItem.getClass().getName();
    }

    public javax.xml.soap.SOAPElement serialize (Object bean,
            SOAPElement rootNode, CustomBindingContext context)
        throws SOAPException; {
        // populate the SOAPElement based on the contents of the
        // object that was passed in.
        return rootNode;
    }

    public Object deserialize (javax.xml.soap.SOAPElement source, 
            CustomBindingContext context)  
        throws SOAPException {
        // create an instance of the appropriate Java object based on
        // the SOAPElement that was passed in.
        return inventoryItem; 
   }
}

Putting it all together

As of now, there are no tools for creating the CustomBindingProvider.xml or the custom binder class automatically, so you'll need to create these by hand. Using the examples above, you should be able to put together both of these artifacts using Rational Application Developer or a text editor.

Once you've created these two items, the next step is to package them up in a custom binder jar file so that you can use it to develop and deploy your Web services application. The best thing to do is to create a new jar file (either manually or using Rational Application Developer) and include in it the binder class, along with the CustomBindingProvider.xml. Remember, the XML file must be saved under the path /META-INF/services/CustomBindingProvider.xml.

With the custom binder now assembled, you're ready to develop the rest of your application. If you're using the WebSphere Web services command line tools (Java2WSDL and WSDL2Java) to develop your application, run the following command:

WSDL2Java.sh [your normal options] -classpath /temp/mybinder.jar [wsdl file name]

As you can see, the only change you need to make to your normal WSDL2Java usage is to include the path to the binder jar you created. By doing this, the WSDL2Java tool searches the classpath for all available instances of the CustomBindingProvider.xml and configures itself appropriately. The classes and deployment descriptors that are generated should reflect this and should now contain your specific data type in place of the SOAPElements that they had before.

If you're using Rational Application Developer, all you need to do is ensure that the custom binder jar is added as an external jar file. Rational Application Developer addds all of these jar files to the classpath prior to invoking the WSDL2Java and Java2WSDL tools.

Figure 2. Include a Custom Binding jar in Rational Application Developer
Include a Custom Binding jar in Rational Application Developer

Conclusion

Using the information outlined above, you should now be able to create WebSphere-based Web service applications that can map some of the more complex schema types not covered by JAX-RPC. The interfaces created now should look more like what is expected by someone trying to use your application and no longer require users to have an in-depth understanding of SAAJ and the expected SOAPElement structure.

As mentioned earlier, the purpose of this article was mostly to provide an overview of Custom Data Binding and how it can benefit your application. The next article in this series will provide an in-depth look at a Custom Binder class that we'll use to serialize and deserialize data types based on a user-defined type mapping (in other words, not using a specific data binding technology). We'll also discuss a few useful tips to keep in mind when developing your specific Custom Binders.

In future parts of this series, we'll discuss specific examples of how to integrate different data binding technologies, including JAX-B 2.0, EMF/SDO and XML Beans.


Download

DescriptionNameSize
code samples in zip formatsample_files.zip  ( HTTP | FTP | Download Director Help )17KB

Resources

Learn

Get products and technologies

  • Build your next development project with IBM trial software, available for download from developerWorks.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, SOA and web services
ArticleID=102518
ArticleTitle=Web Services Custom Data Binding, Part 1: How to choose a custom mapping technology for Web services
publish-date=01252006