Wednesday, August 22, 2007

How to make a JAX-WS client reuse existing classes for data binding (3).

Now we have created the customization file for data binding (doesn't matter if manually or using XJC capabilities). The last think we need is to configure the JAX-WS toolkit to use this customization when creating client classes.
  • For the command line wsimport (reference implementation) we just use the option:
    -b  Specify external JAX-WS or JAXB binding files
    (Each <file> must have its own -b)
  • For wsimport ant integration we use
    <wsimport ...>
    <binding dir="${conf.dir}/" includes="a.episode"/>
    </wsimport>
  • For NetBeans IDE 5.5 and higher, you can use the GUI for WSDL customization. See WsdlCustomizer or JAX-WS Customizations made easy with NetBeans 5.5 for more information. Basically you need to create a web service reference, right click, choose Edit Web Service Attributes, go to the WSDL customization -> External binding file and then browse to your binding file. If the file does not appear in the file list because of filter, just go to the right directory and type its name. NetBeans automatically updates the wsimport ant task in jaxws-build.xml file with <binding> tag.

Tuesday, August 21, 2007

How to make a JAX-WS client reuse existing classes for data binding (2).

The JAXB 2.1 binding customization is described in the JAXB 2.1 specification, chapter "CUSTOMIZING XML SCHEMA TO JAVA REPRESENTATION BINDING". For our purpose we will use following binding declarations:
  • <class> customizes the binding of a schema component to a class. It's ref attribute if specified, is the name of the value class that is provided outside the schema compiler. This customization causes a schema compiler to refer to this external class, as opposed to generate a definition. It must include the complete package name.
  • <typesafeEnumClass> this declararion has the same means of ref attribute and can be used for mapping Enum's.
Using these binding declarations we can create a JAXB customization file that binds represenation of some XML element to provided classes. An example which maps two complex types and enumeration simple type to java classes in your.packagage follows:
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="YourSchemaFile" node="/xs:schema">
<jxb:bindings node="//xs:complexType[@name='employerResult']">
<jxb:class ref="your.package.employerResult">
</jxb:class>
</jxb:bindings>
<jxb:bindings node="//xs:complexType[@name='phoneResult']">
<jxb:class ref="your.package.PhoneResult">
</jxb:class>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='eStatus']">
<jxb:typesafeEnumClass ref="your.package.EStatus"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
Note that the form of customization document slightly differs for inlined / imported XML schema into the WSDL. In our case the schema is imported, so we can directly use standard JAXB 2.1 customization file. See schema customization link for more information. I would recommend keeping "client" customization in an external file and leave the WSDL general and clean, but here you can see an example of inline binding declarations incorporated directly to the WSDL.

If you are using the reference implementation of JAX-WS 2.1 and underlying JAXB 2.1 you can make thinks even simpler by using Separate compilation in the JAXB RI 2.1. Based on this technique, you can let the XJC compiler to generate binding declarations for you. The counterpart is that the generated binding declaration uses SCD references instead the XPath, what makes the customization file non-portable to other JAXB toolkit. Lets say the data binding of your web service is defined in the a.xsd schema included in WSDL. You can run
xjc -episode a.episode a.xsd 
The XJC compiler generates the data binding classes and additionally creates the a.episode customization documents like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings version="2.1" xmlns="http://java.sun.com/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="http://processed.schema.namespace/">
<schemaBindings map="false"/>
<bindings scd="~tns:logOnUser">
<class ref="processed.schema.namespace.LogOnUser"/>
</bindings>
<bindings scd="~tns:logOnUserResponse">
<class ref="processed.schema.namespace.LogOnUserResponse"/>
</bindings>
</bindings>
</bindings>
The document contains binding declaration that explicitly bind XML elements to classes generated by XJC. All what we need is to re-allocate the ref attribute of generated binding declaration to own class implementation we want to reuse. [Note: The main purpose of generated episode file during Separate compilation is to provide customization that makes XJC reuse generated classes for binding other schemas with same elements. In the case of our web service it serves as a template for creating customization of a.xml itself].
Updating the generated template is straightforward if our web service uses Document Bare style. If the web service uses Document Wrapped then the result object is wrapped in the response bean. It does not have much sense to provide even own implementation of wrapper beans in that case. We can let the JAXB generate the wrapper classes and use own classes only for representing actual parameters and result objects. In example it means we remove the binding declaration for LogOnUserResponse and let reuse only the implementation of LogOnUser that represents the result parameter.
The last think you may need is to remove the <schemaBindings map="false"/> declaration which might cause some errors to JAX-WS toolkit. The resulted file may look like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings version="2.1" xmlns="http://java.sun.com/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="http://processed.schema.namespace/">
<bindings scd="~tns:logOnUser">
<class ref="your.package.LogOnUser"/>
</bindings>
</bindings>
</bindings>

How to make a JAX-WS client reuse existing classes for data binding (1).

This tutorial describes how one can configure a JAX-WS client to reuse already existing classes for web service data binding, i.e. as a java representation of in/out parameters communicated with a web service via XML.

There exists followings use cases for which you may need this ability:
  • Reuse the same parameter/result classes on the server and client. You can introduce a common javabean package for representing entities in both client and server components. Additionally you can implement some methods on the top of the javabeans. The functionality will be in turn available on both server and client side. This approach keeps general web service interoperability based on WSDL contract for 3'rd party clients, while your own clients can benefit from functional code reuse.
  • Reuse the same binding classes among more clients. If yours clients serve the same ws endpoint, or your new client serves a superset of an existing one, then you can consider introducing a common package for data representation and reuse it for data binding from all your clients.
  • You have been given classes for data presentation on your client. In that case you can benefit from the JAX-WS toolkit capabilities to provide xml <->java binding right to designated classes, instead of manually coding some adaptors.

Requirements: This tutorial assumes that you use
JAX-WS 2.1 and JAXB 2.1 compliant toolkits. Part of this scenario relies on proprietary tools and features of the reference implementation provided by java-net community.

The standard way to create a JAX-WS client is to get the WSDL description of a web service and let the JAX-WS toolkit automatically generate web service interface and classes for its local proxy which provides communication with remote web service endpoint. The JAX-WS simultaneously generates classes for data binding, e.g. classes that represents data which are sent to and received from a web service in an XML form. All those classes are generated according standardized procedure described in the JAX-WS 2.1 specification, chapter WSDL 1.1 to Java Mapping (packaging, naming, structure). The JAX-WS specification in turn defers data binding to the JAXB specification and its default rules for java class generation from XML schema. The standard procedure how classes are generated can be customized. In the following text I describe how to create and use a particular customization which tells JAX-WS to use existing classes for XML data presentation instead of generating new ones.

The exact way how the customization works is described in the JAX-WS 2.1 specification, chapter Customization. Put succinctly the customization is based on binding declarations provided to the JAX-WS toolkit at the time of client generation. Binding declarations are expressed in XML based binding language. They can be directly included in the WSDL document which java mapping they customize or reside in an external file that points to the related WSDL file. Binding customization can include any JAXB 2.1 binding declaration in order to customize data binding.

TestPost

This is a test.