Web services hints and tips: avoid anonymous types

Anonymous XML types can sometimes cause problems in Web services. This article explains these problems and describes how to avoid them.

Share:

Russell Butek (butek@us.ibm.com), Certified IT Specialist, IBM

Russell Butek is an IBM SOA/Web services consultant. He has been one of the developers of IBM's WebSphere Web services engine. He has also been 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.



Shannon Kendrick (kendrick@ibm.com), Senior IT Specialist, IBM

Shannon Kendrick is a Senior IT Specialist with IBM Interactive. Shannon works primarily in Java EE application development for a variety of clients, and he frequently utilizes Web services as part of the client solution.



30 August 2011

Also available in Chinese Russian Japanese Vietnamese

Introduction

We often see Web service XML schemas written using anonymous types. It is unlikely that the authors of such schemas realize the potential problems that they may cause when they build such schemas. This article codifies issues that may arise from using anonymous types in hopes that readers will avoid them.

What is an anonymous type?

An anonymous XML type is one which is embedded within an xsd:element. Since it is embedded within an xsd:element, it is not named. For example, see listing 1.

Listing 1. Anonymous 'person' type
<xsd:element name="person">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="first" type="xsd:string"/>
      <xsd:element name="last" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

The complexType within the element named "person" has no name itself, so it is anonymous. You can convert this anonymous type into a named type by following these simple steps:

  • Move the complexType definition out to the global scope.
  • Give the complexType a name attribute.
  • Give the global element a type attribute which refers to the newly named complexType.

We followed these steps to transform listing 1's anonymous type into listing 2's named type.

Listing 2. Named Person type
<xsd:element name="person" type="Person"/>
<xsd:complexType name="Person">
  <xsd:sequence>
    <xsd:element name="first" type="xsd:string"/>
    <xsd:element name="last" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

The schemas in listing 1 and listing 2 are logically identical. Either one of them can be used to validate the XML instance shown in listing 3.

Listing 3. Named Person type
<person>
     <first>John</first>
     <last>Doe</last>
</person>

What's wrong with anonymous types?

We will use the schemas in listings 4 and 5 throughout the rest of this discussion. Listing 4 does not define a single named type. All types are anonymous. For comparison, listing 5 shows the equivalent schema with named types. We applied the steps above to listing 4 to create listing 5.

Listing 4. The account element defined with anonymous types
<xsd:element name="account">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="number" type="xsd:int"/>
      <xsd:element name="person">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="firstName" type="xsd:string"/>
            <xsd:element name="lastName" type="xsd:string"/>
            <xsd:element name="otherNamesOnAccount" minOccurs="0" maxOccurs="unbounded">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element name="person">
                    <xsd:complexType>
                      <xsd:sequence>
                        <xsd:element name="firstName" type="xsd:string"/>
                        <xsd:element name="lastName" type="xsd:string"/>
                      </xsd:sequence>
                    </xsd:complexTypeb>
                  </xsd:element>
                  <xsd:element name="relationshipToAccountOwner" type="xsd:string"/>
                </xsd:sequence>
              </xsd:complexType>
            </xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>
Listing 5. The account element defined with named types
<xsd:element name="account" type="tns:Account"/>

<xsd:complexType name="Account">
  <xsd:sequence>
    <xsd:element name="number" type="xsd:int"/>
    <xsd:element name="person" type="tns:AccountOwner"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="AccountOwner">
  <xsd:sequence>
    <xsd:element name="firstName" type="xsd:string"/>
    <xsd:element name="lastName" type="xsd:string"/>
    <xsd:element name="otherNamesOnAccount" minOccurs="0" maxOccurs="unbounded"
        type="tns:OtherNameOnAccount"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="OtherNameOnAccount">
  <xsd:sequence>
    <xsd:element name="person" type="tns:Person"/>
    <xsd:element name="relationshipToAccountOwner" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Person">
  <xsd:sequence>
    <xsd:element name="firstName" type="xsd:string"/>
    <xsd:element name="lastName" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

Why do we dislike the anonymous types in listing 4?

  • There is no re-use
  • Anonymous types still often must be named
  • Listing 4 is not as elegant as listing 5

The rest of this article will go into details on each of these three points.


No re-use

This is our primary issue with anonymous types. When a type is defined anonymously within an element, only that element can be of that type. If you wish another element elsewhere to be the same type, the best you can do is to cut/paste the anonymous type definition into the new element.

For instance, the firstName/lastName pair of elements is duplicated in listing 4 – one set within the outer person element and the other within the inner person element. To enable re-use, these two elements should be placed into their own named type. Without such a named type, the elements were simply copied from one point of the schema to another.

Note that in listing 5 we now have such a named type: Person. Listing 5 is the named equivalent to listing 4; we did not make any changes that would affect the structure of XML instances. But now that we have a named type for Person, we could further improve the schema in listing 5 by re-using the Person type within AccountOwner.


Anonymous types still often must be named

Even if you do not care about re-use, there is still a potential hazard to using anonymous types. Consider how an XML schema is used. For instance, in a Web service definition, there is a good chance that the XML schema will map to a programming language. If so, then within that language, types likely can no longer be anonymous. They must be named somehow, and the name must be derived from the surrounding schema. No matter what rules you come up with for such a derivation, there will likely exist some scenario which breaks those rules.

For example, the JAXB specification’s rules for mapping XML schema to Java breaks down with the schema defined in listing 4. JAXB defines that an anonymous type’s class takes on a name derived from the containing element. Moreover, embedded anonymous complex types in XML become inner classes in Java. According to JAXB, the XML schema in listing 4 will map to the following Java classes:

  • Account
  • Account.Person
  • Account.Person.OtherNamesOnAccount
  • Account.Person.OtherNamesOnAccount.Person

Java does not allow nested classes to share names with containing classes. You will have a compile-time error something like: "The nested type Person cannot hide an enclosing type".

Our solution to this problem is to name all types as we did in listing 5. You can see that we mostly applied the name derivation rules that JAXB uses – deriving the name of the Java type from the name of the enclosing element. But we did not do it for all types, otherwise we would have ended up with two "Person" types. So we arbitrarily renamed the first "Person" type to "AccountOwner".

The JAXB binding file

While we prefer our solution, that solution requires you to change the XML schema. For those cases where you cannot change the schema, JAXB provides another solution. JAXB allows a user to write a binding file which tells the JAXB engine how to map XML to Java. The authors of the JAXB specification knew that a specified mapping would not always work for everyone in every situation, so they provided this mechanism to deviate from the standard. Listing 6 is the binding file which will tell the JAXB generator to modify the class generated from the anonymous complexType under the first person element so that it is named "AccountOwner".

Listing 6. A JAXB binding file needed to fix the issue with listing 4
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="htp://www.w3.org/2001/XMLSchema-instance" 
mlns:xsd="http://www.w3.org/2001/XMLSchema"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb 
http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
		jaxb:version="2.1">
  <jaxb:bindings schemaLocation="Anonymous.xsd" node="/xsd:schema
    /xsd:element[@name='account']/xsd:complexType/xsd:sequence
    /xsd:element[@name='person']/xsd:complexType">
    <jaxb:class name="AccountOwner"/>
  </jaxb:bindings>
</jaxb:bindings>

The inner jaxb:bindings element contains a schemaLocation attribute to tell the engine which schema this binding file affects; and it contains a node attribute whose value is an XPath expression for the element for which you want to apply the special binding. The jaxb:class element then tells you that the JAXB class generated from the given XPath’s element will be named "AccountOwner". For more information on the JAXB mapping file, see the Resources section.

JAXB is robust enough to allow you to name anonymous types as you need to via the binding file. But it adds complexity to the process of building your service. And you cannot depend on all language mappings to give you this same level of functionality. So if you have the freedom to modify the schemas, it is best to avoid anonymous types.


Not as elegant

Our final complaint about listing 4 is that it is not as elegant as listing 5. We freely admit that this last reason is purely a matter of opinion. But in our opinion, anonymous types aren’t as readable as named types; a deeply nested XML structure is almost always more difficult to understand readily. Structures of anonymous types are more difficult to discuss than structures of named types.


Summary

Anonymous types should be avoided for a number of reasons:

  • they do not allow re-use;
  • they may cause problems when a mapping must name anonymous types;
  • they are not as elegant as named types.

These issues can be remedied by converting anonymous types to named types. In the case of JAXB's mapping from XML schemas to Java, if you are not able to change the schema, you can provide a JAXB binding file to the JAXB engine to alleviate any problems you may encounter.

Resources

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 SOA and web services on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=754620
ArticleTitle=Web services hints and tips: avoid anonymous types
publish-date=08302011