Skip to main content

Tip: xsd:any: A cautionary tale

Russell Butek (butek@us.ibm.com), Web Services Consultant, IBM
Russell Butek is an IBM Web Services Consultant. He was one of the developers of the IBM WebSphere Web services engine. He is also a member the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of the IBM CORBA ORB and an IBM representative on a number of OMG task forces, including chairing the portable interceptor task force.

Summary:  xsd:any is a popular feature for people designing XML schema. But it's often more trouble than it's worth. Explore some of the shortcomings of xsd:any, both in XML itself and in the JAX-RPC Java language binding, so that, even if you decide to use xsd:any, you will be more prepared to deal appropriately with it.

Date:  13 Dec 2005
Level:  Intermediate
Activity:  4431 views

Introduction

Why do people like to use xsd:any? I hear many reasons: for loose coupling, to enable versioning, for completely flexible polymorphism. All of these reasons come down to not changing the API. That's a noble reason, but in practice, using xsd:any is neither noble nor practical. If you're working in a dynamic environment, purely with XML, then xsd:any may, indeed, be appropriate. But most people do not like the complexity of dynamic access to XML (in other words, the SAX or DOM or SAAJ programming models), and even when they do, there are gradations of dynamicity. And XML rarely exists in a vaccuum. XML almost always maps to or interacts with something else. For instance, an XML schema might exist as part of a Web service, which means that you will likely deal with a language binding. So you should be aware of how that language binding maps xsd:any to the given language. In this tip, I focus on the JAX-RPC Java™ language binding.


An example Web service using xsd:any

Let's look at the example WSDL file in Listing 1. It is a simple veterinary clinic Web service. It defines an operation called registerPet, whose input message contains an xsd:any. This WSDL also defines a couple of pet types: cat and fish.


Listing 1. Veterinarian service WSDL using xsd:any
				<?xml version="1.0" encoding="UTF-8"?>
<definitions
    targetNamespace="urn:any"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="urn:any"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns="http://schemas.xmlsoap.org/wsdl/">
  <types>
    <schema
        targetNamespace="urn:any"
        xmlns:tns="urn:any"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns="http://www.w3.org/2001/XMLSchema">
      <complexType name="Cat">
        <sequence>
   	      <element name="name" type="xsd:string"/>
   	      <element name="breed" type="xsd:string"/>
        </sequence>
      </complexType>
      <complexType name="Fish">
        <sequence>
   	      <element name="name" type="xsd:string"/>
   	      <element name="saltWater" type="xsd:boolean"/>
        </sequence>
      </complexType>
      <element name="registerPet">
        <complexType>
          <sequence>
            <any namespace="##any"/>
          </sequence>
        </complexType>
      </element>
      <element name="registerPetResponse">
        <complexType>
          <sequence/>
        </complexType>
      </element>
    </schema>
  </types>
  <message name="registerPetRequest">
    <part name="registerPetRequest" element="tns:registerPet"/>
  </message>
  <message name="registerPetResponse">
    <part name="registerPetResponse" element="tns:registerPetResponse"/>
  </message>
  <portType name="Vet">
    <operation name="registerPet">
      <input message="tns:registerPetRequest"/>
      <output message="tns:registerPetResponse"/>
    </operation>
  </portType>
  <binding name="VetSOAP" type="tns:Vet">
    <soap:binding style="document"
        transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="registerPet">
      <soap:operation/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="VetService">
    <port name="VetSOAP" binding="tns:VetSOAP">
      <soap:address location="http://localhost:9080/VetService/services/Vet"/>
    </port>
  </service>
</definitions>

The xsd:any parameter to registerPet can be either of the following:

  • An instance of a Cat or a Fish
  • An instance of some other pet type that may be defined elsewhere or at another time.


xsd:any deviates from the intent of WSDL

Notice that the two bullet points above are not defined in the WSDL. I made them up. WSDL is the Web Services Description Language. Its charter is to describe an interface to a service as completely as possible. When you use xsd:any, you deviate from this intent of WSDL.

This service is better than many

This service actually defines some of the types which will be sent as the xsd:any parameter. While this WSDL does not fully describe the contract of the service, at least the types that it does define are a pretty good hint about what the xsd:any may contain. I've seen many WSDL definitions which wouldn't even give you that much. They would just give you the xsd:any (or, worse yet, an xsd:string which is assumed to contain an XML instance in string form). Everything you have to know about the parameter is provided through some out-of-band mechanism.

The first bullet states that the parameter is going to be a cat or a fish. But the WSDL doesn't tell you that. All it says is that the parameter can be anything. Given that this is a veterinarian service, it likely won't handle orders or insurance claims or tax statements -- but you're just guessing; the WSDL doesn't tell you that.

A better approach to this pseudo-polymorphism would be to define true polymorphism. Define a base type, called Pet, and rewrite Cat and Fish to extend Pet.

The second bullet states that other types will be defined elsewhere or at another time. That tells me that the WSDL isn't the complete interface for this service. It may appear that you can change the service and keep the API unchanged, but since this WSDL isn't the complete API, that's a false statement. For a client using this WSDL to communicate successfully to this service, the WSDL is not enough. Can a client send an alligator to the service? Just by looking at the WSDL, you don't know (I don't know too many vets who would support an Alligator type!). You need some additional, out-of-band definitions.


JAX-RPC is not particularly friendly with xsd:any

Finally, in order to use this service, you have to map this WSDL to some language binding. I'll pick on the JAX-RPC specification. According to JAX-RPC, xsd:any maps to javax.xml.soap.SOAPElement, a type defined in the SAAJ specification. SAAJ is a DOM-like API used to access XML instances in a SOAP message. SAAJ is a very dynamic, very low-level, and not particularly friendly means of accessing XML instance data. See Listing 2 for the Java interface for the WSDL in Listing 1.


Listing 2. Java interface for WSDL using xsd:any
				package any;

public interface Vet extends java.rmi.Remote {
    public void registerPet(javax.xml.soap.SOAPElement any)
        throws java.rmi.RemoteException;
}

(For a discussion of a SAAJ implementation, see the Resources for a link to "how to use the SAAJ API".)

This may be a very good mapping for a dynamic programmer, but the rest of us would rather deal with the generated classes Cat and Fish rather than with SOAPElement. It would be nice if you could just push a Cat or Fish into a SOAPElement, but there is no SAAJ-specified way to do so. JAX-RPC dictates that xsd:any maps to SOAPElement, yet it fails to provide a means by which you can transform instances of the classes into or from SOAPElement.

If you are comfortable working with DOM, SAX, or SAAJ, then xsd:any will be no problem for you. However, keep in mind the users of your WSDL. Just because you are comfortable with this level of programming, will the other users of your WSDL be comfortable with it as well?


Thoughts about xsd:anyType

An alternative to xsd:any is xsd:anyType (see Listing 3 for the WSDL -- the change from Listing 1 is highlighted in bold -- and Listing 4 for the Java interface). The disadvantage of xsd:anyType is that JAX-RPC does not define a mapping for it. So even if a vendor maps this XML type, you cannot write portable code which uses it. With that said, however, an advantage to this type is that some vendors, like IBM, map it to a somewhat useful type, like java.lang.Object. In the case of WebSphere Application Server's SOAP engine, if the method takes a parameter of type java.lang.Object, then you can send any Java object to that method and, as long as it is an XML-compliant object, it will then be serialized into the SOAP message. Conversely, on the receiving side, if the SOAP engine knows how to deserialize the XML instance into a Java object, it will do so. If the engine does not know how to deserialize the object, the receiver will get a SOAPElement, just as it would for xsd:any.

Keep in mind that, even though xsd:anyType may seem better than xsd:any, it is not a supported JAX-RPC mapping. So it is only better if:

  • You don't care that your code is not portable.
  • The underlying platform for the implementations of both the service and the clients to the service have some mapping for xsd:anyType.


Listing 3. Veterinarian service WSDL using xsd:anyType
				<?xml version="1.0" encoding="UTF-8"?>
<definitions
    targetNamespace="urn:any"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="urn:any"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns="http://schemas.xmlsoap.org/wsdl/">
  <types>
    <schema
        targetNamespace="urn:any"
        xmlns:tns="urn:any"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns="http://www.w3.org/2001/XMLSchema">
      <complexType name="Cat">
        <sequence>
   	      <element name="name" type="xsd:string"/>
   	      <element name="breed" type="xsd:string"/>
        </sequence>
      </complexType>
      <complexType name="Fish">
        <sequence>
   	      <element name="name" type="xsd:string"/>
   	      <element name="saltWater" type="xsd:boolean"/>
        </sequence>
      </complexType>
      <element name="registerPet">
        <complexType>
          <sequence>
            <element name="pet" type="xsd:anyType"/>		
          </sequence>
        </complexType>
      </element>
      <element name="registerPetResponse">
        <complexType>
          <sequence/>
        </complexType>
      </element>
    </schema>
  </types>
  <message name="registerPetRequest">
    <part name="registerPetRequest" element="tns:registerPet"/>
  </message>
  <message name="registerPetResponse">
    <part name="registerPetResponse" element="tns:registerPetResponse"/>
  </message>
  <portType name="Vet">
    <operation name="registerPet">
      <input message="tns:registerPetRequest"/>
      <output message="tns:registerPetResponse"/>
    </operation>
  </portType>
  <binding name="VetSOAP" type="tns:Vet">
    <soap:binding style="document"
        transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="registerPet">
      <soap:operation/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="VetService">
    <port name="VetSOAP" binding="tns:VetSOAP">
      <soap:address location="http://localhost:9080/VetService/services/Vet"/>
    </port>
  </service>
</definitions>


Listing 4. Java interface for WSDL using xsd:anyType
				package any;

public interface Vet extends java.rmi.Remote {
    public void registerPet(java.lang.Object pet)
        throws java.rmi.RemoteException;
}


Summary

Although it may seem like a good idea to use xsd:any in your Web service's XML schema, there are pitfalls to doing so: you are deviating from the intent of WSDL, and the language mapping of xsd:any may not be easy to use. Although I won't go so far as to say using xsd:any is a bad practice, I do hope this tip has given you a better awareness of problems you may encounter before you encounter them.


Resources

Learn

Get products and technologies

Discuss

About the author

Russell Butek is an IBM Web Services Consultant. He was one of the developers of the IBM WebSphere Web services engine. He is also a member the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of the IBM CORBA ORB and an IBM representative on a number of OMG task forces, including chairing the portable interceptor task force.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services, XML
ArticleID=100535
ArticleTitle=Tip: xsd:any: A cautionary tale
publish-date=12132005
author1-email=butek@us.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers