Menu

Schema Binding for Java Web Services

May 26, 2004

Mitch Gitman

Sometimes you just wish software architects weren't so creative or, at least, were more coordinated. It seems that's what happened with SOAP, the standard format for web services messages. The SOAP specification started out defining a lot of protocol-specific XML structures that now, in hindsight, could obviously better be delegated to the W3C XML Schema language, the whole purpose of which is to define the structure of XML documents. It's a disconnect that the Java community is still working out.

In this article we'll explore the oft-misunderstood relationship between Java web services platforms and the W3C XML Schema (WXS) binding frameworks that convert between XML and XML-agnostic objects. And we'll look at how to leverage schema binding using various Java Web services toolkits and runtimes.

Reconciling Web services with XML Schema

In May 2000, when the World Wide Web Consortium published SOAP 1.1, the W3C XML Schema specification was still only in draft stages.

SOAP 1.1 encourages a way of encoding XML that relies on placing simple type values in element bodies. But where SOAP encoding, as it is called, really digresses from WXS is in its use of in-document references and a SOAP-specific Array type.

SOAP 1.1 also suggests a way of associating SOAP messages with remote procedure calls. RPC imposes certain conventions and restrictions on the XML elements that correspond to parameters or return values and the method-matching XML elements that automatically wrap them.

By the time in May 2001 the W3C finalized its XML Schema specification, more WXS-reliant alternatives to SOAP encoding and RPC style had arisen.

As opposed to SOAP encoding, literal XML usage says XML should be written precisely the way it's defined in a schema. No more complicated references or SOAP-encoded arrays. In a Web Services Description Language (WSDL) 1.1 document, a use attribute in certain SOAP-specific elements can be set to encoded or literal.

As opposed to RPC style, document style tells a runtime to write the XML exactly as it's defined in the WSDL. In the WSDL, each message element should contain a single part element, which in turn refers to an element defined in a schema. Conveniently, the XML schemata appear directly -- or indirectly via imports -- under the types element of a WSDL, using a path like so:

/wsdl:definitions/wsdl:types/xsd:schema

In WSDL, a style attribute in certain SOAP-binding elements can be set to "rpc" or "document".

Document/literal Web services are well on their way to replacing RPC/encoded as an industry standard. The Web Services Interoperability Organization (WS-I), a consortium whose goal is make sure Web services and clients play nice together, published in August 2003 a set of guidelines called the Basic Profile Version 1.0a. The Basic Profile prohibits the use of SOAP encoding; it does allow RPC style, although the RPC/literal combination has never caught on.

The nice thing about document/literal is that it forces the actual payload of a SOAP message to be defined entirely using W3C XML Schema, independent of SOAP and WSDL. The child of the soap:Body element, as shown in the SOAP message structure below, can stand alone as its own XML document:


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" >

    <soap:Header>

        <!-- header element(s) -->

    </soap:Header>

    <soap:Body>

        <!-- body element defined independent of SOAP -->

    </soap:Body>

</soap:Envelope>

This is the kind of encapsulation that should make a design patterns aficionado go weak at the knees. Not only could the SOAP body's contents readily be validated against a schema, but if the web services platform leverages a schema binding framework with a public API, the same schema can be used to serialize XML not just to a SOAP message but to any destination: a file, as a node within a larger document, whatever.

Here's another nice thing, if you consider a whole can of worms a nice thing. Once you're using a full-fledged schema binding framework, you can customize how you bind between Java classes and WXS data types. Consider the beginning of a JavaBean-style class definition below:

public class BasicDataBean implements java.io.Serializable {

	private String key;

	public String getKey() { return key; }

	public void setKey(String key) { this.key = key; }

...

Simple question: do you define the key property as an XML element or attribute? With SOAP encoding, you have no choice but to make it an element. With literal use, there are two ways to go:

  • Just as with SOAP encoding, the binding toolkit makes the choice for you. This is what the open-source Web services platform Apache Axis 1.2 does.
  • The toolkit gives you a choice.

If you don't want to control the XML in your web service, the former, default-only approach is an acceptable option. But if you do want to exploit the schema's constructs or you're generating a client for a service that does, then the latter approach, involving a real schema binding framework, is required.

A Java binding framework provides a schema-to-Java tool, possibly also a Java-to-schema tool. If a web services provider incorporates the schema binding provider, then WSDL-to-Java and Java-to-WSDL tools should perform a superset of the schema-only tools' functionality.

So where do the binding/mapping customizations go? Some "to-Java" tools place them in the plumbing of the generated implementation classes themselves, although that tends to rule out a "Java-to" reverse conversion. Other to-Java tools produce an extra output besides source code, namely a proprietary XML mappings file, which in turn becomes an extra input to the corresponding Java-to tool (if present). Accordingly, the runtime checks the customizations as it translates between XML instance documents and objects.

Employing the same XML serializer on both ends

We're ready to try to exploit the synergy between schema binding and web services. We'll use what we might call a naïve implementation, where we define the same XML document for publishing over the Web service and for serializing to disk. Suppose the service endpoint interface defines these methods:

public void update(FooDocument foo) throws

java.rmi.RemoteException; public FooDocument getFoo() throws

java.rmi.RemoteException;

The FooDocument class corresponds to a foo.xsd schema definition that gets imported into the web service's generated WSDL. The web service runtime receives an update SOAP message and automatically deserializes the XML into a FooDocument instance. (Normally, you'll use a "wrapped" interpretation of a document-style web service where the request soap:Body element's child is not the foo element but rather an extra wrapper element that the Web service platform has automatically defined in the WSDL.)

The implementation of update should do something like:

public void update(FooDocument foo) throws java.rmi.RemoteException {

    QName qname = new javax.xml.namespace.QName(

                Pk_Foo.NAMESPACE, "foo", Pk_Foo.PREFIX);

    mPersist.writeObject2Document(qname, 

                getFile(mDataRoot, Pk_Foo.FILENAME));

}

The member variable mPersist is an instance of a Persistence interface we define:

public interface Persistence {

    public void writeObject2Document(QName qname,

            File file) throws SomeCustomException;



    public Object readDocument2Object(Class klass,

            QName qname,

            File file) throws SomeCustomException;

    }

}

You can then implement the Persistence interface using the same binding framework the Web services platform uses. The writeObject2Document implementation obtains a writer or output stream and calls an appropriate object serialization method in the binding framework API. Likewise, readDocument2Object, which is called by getFoo, calls the appropriate deserialization method. The translation between an entire XML document and an entire object graph should be accomplished in a few method calls; no need to write DOM or SAX code or otherwise get your hands dirty with the XML.

There are a few reasons this example might be considered a naïve implementation:

  • Usually your persistence store is not the file system but a relational database where you probably don't want to spew text documents.
  • Even then, you might have a slicker way of saving the XML document than by going directly to disk.
  • The data structure you send across the wire perhaps shouldn't be as verbose as the one you save to disk.

The state of W3C XML Schema binding support

The following table shows a sampling of web services implementations together with the XML Schema binding components they use, plus how those components customize the bindings between XML Schema data types and Java classes:

Web services platform XML Schema binding framework Where customizations are stored
webMethods Glue 5.0.1 Its own proprietary Electric XML+. .map files.
Systinet WASP Server for Java 4.7.1 (new version is 5.0) Its own. .xmap files.
Apache Axis 1.2 beta Its own. No customizations allowed.
Apache Axis 1.2 beta with Castor Castor. The Castor-generated classes, or a mapping file for composed classes.
BEA WebLogic Server 8.1 SP2 XMLBeans. The generated XMLBeans classes.

Glue, with Electric XML+, and WebLogic Server, with XMLBeans, seamlessly allow you to serialize XML interchangeably within Web services and without. WASP requires some do-it-yourself to use its XML serializer independent of SOAP. The Axis+Castor marriage is more of a kludge.

It's also worth mentioning the Java Web Services Developer Pack 1.3. The JWSDP contains Sun's reference implementation of the JAX-RPC 1.1 specification for mediating between the Java world and the SOAP/WSDL worlds. The Java API for XML-based RPC, now in version 1.1, has had to evolve from its RPC/encoded legacy, but its default bindings do influence the other SOAP engines listed above.

The JWSDP also contains Sun's implementation of the Java Architecture for XML Binding (JAXB) v1.0.2, a standards-based attempt at a binding framework. But even though the JWSDP is Basic Profile-conformant, there's no real integration between the JAX-RPC and JAXB implementations. To accomplish what's described in our nave example, you'll have to wait until the JWSDP implements the 2.0 versions of the JAX-RPC and JAXB specifications, which at long last are being coordinated. Final drafts are expected by the end of 2004.