IBM WebSphere Developer Technical Journal: Web Services Value Type Inheritance and Interoperability

While inheritance is common in Java programming, it can cause some headaches when you consider it in the context of Web services. This article discusses how value types are inherited in XML schema, how this applies in the mapping from Java objects to WSDL, and how the WebSphere tools and run time deal with this issue.

Share:

Kyle Brown (brownkyl@us.ibm.com), Senior Technical Staff Member, IBM Software Services for WebSphere

Kyle Brown is a Senior Technical Staff Member with IBM Software Services for WebSphere. Kyle provides consulting services, education, and mentoring on object-oriented topics and J2EE technologies to Fortune 500 clients. He is a co-author of Enterprise Java Programming with IBM WebSphere, the WebSphere AEs 4.0 Workbook for Enterprise Java Beans, 3rd Edition, and The Design Patterns Smalltalk Companion. He is also a frequent conference speaker on the topics of Enterprise Java, OO design, and design patterns.


developerWorks Professional author
        level

19 January 2004

Introduction

Inheritance and polymorphism are fundamental to object-oriented (OO) programming. No one doubts their importance. However, as we look beyond OO development to component development, and especially service development in a Services Oriented Architecture (SOA), things become more complicated. While services appear to be (on the outside) very large-grained distributed objects, they can, in fact, be implemented in any of a number of ways, in both OO and non-OO languages.

It is this fact that has generally kept discussions of inheritance outside the universe of discourse for Web services. As such, WSDL 1.1 did not even contain a mechanism allowing for interface inheritance. It did allow for operator overloading, but in the new WSDL 1.2 specification [WSDL12], even that has been removed to allow for a better structured portType inheritance mechanism.

Even though inheritance for WSDL port types has at least been an active topic for discussion, the same has, strangely, not been true of inheritance among the WSDL types that are used as arguments for methods by WSDL port types. This silence is odd, considering that there is a simple mechanism in XML Schema that can be used to provide the same effect as implementation inheritance: the extension mechanism.

The extension mechanism is described in Part 0 (the primer) of the W3C XML Schema recommendation. You begin by defining a complexType element in XML Schema, and then use the extension tag to declare that another complexType extends the "base" type. For instance, the following example from the XML Schema recommendation shows how this is done:

<complexType name="Address">
  <sequence>
   <element name="name"   type="string"/>
   <element name="street" type="string"/>
   <element name="city"   type="string"/>
  </sequence>
 </complexType>

 <complexType name="USAddress">
  <complexContent>
   <extension base="ipo:Address">
    <sequence>
     <element name="state" type="ipo:USState"/>
     <element name="zip"   type="positiveInteger"/>
    </sequence>
   </extension>
  </complexContent>
 </complexType>

Inheritance in the JAX-RPC specification

Given the fact that XML Schema allows such a simple mechanism for value type inheritance, you would expect different Web services tools and specifications to take advantage of this where applicable. It turns out that JAX-RPC, for one, allows this. Section 5.4.1 of the JAX-RPC spec describes how a JAX-RPC compliant Web services implementation should use the XML Schema extension construct to relate inherited value objects together in the WSDL.

In particular, section 5.4 states (when discussing value types, which are used as method arguments and return types in a Service Endpoint Interface), "[a] Java class may implement any Java interface (except the java.rmi.Remote interface) or extend another Java class."

Later, in section 5.4.1, it then describes how these inherited Java classes should be mapped into XML Schema types: "Inheritance of the Java classes is mapped using the derivation of xsd:complexType types using the extension mechanism."

The specification then goes on to provide a simple example of value type inheritance, showing the use of the extension tag in exactly the same way as it was used in the previous example taken from the XML Schema recommendation. This means that a JAX-RPC compliant implementation must support this. It turns out that WebSphere Studio Application Developer Version 5.1 (and by extension WebSphere Application Server V5.02) does fully support this, as should be expected. However, it takes a little bit of work to demonstrate this support, as we show next.


Making argument inheritance work in WebSphere Studio Application Developer 5.1

Let€™s assume we want to build a simple example where you have two related classes, Employee and SalariedEmployee. The base class, Employee, is shown here:

public class Employee implements java.io.Serializable {
     private String name;
     public String getName() {
          return name;
     }
     public void setName(String nm){
          name = nm;
     }
}

The subclass, SalariedEmployee is shown below:

public class SalariedEmployee extends Employee {
	private int salary;
	public int getSalary() {
		return salary;
	}
	public void setSalary(int i) {
		salary = i;
	}
}

Now, assume that we then create a JavaBean named EmployeeFactory to implement our Web service that has the following method:

public String deriveInfoFor(Employee e) {
	String output = "Name="+ e.getName();
	if (e instanceof SalariedEmployee) {
		output+= " Person is a SalariedEmployee ";
		output+= ((SalariedEmployee)e).getSalary();
	}
	else output+= "Person is a Regular Employee ";
	return output;
}

We then have to create a Service Endpoint Interface (SEI) to meet the requirements of the JAX-RPC specification:

public interface EmployeeFactoryIF extends java.rmi.Remote{
	public abstract String deriveInfoFor(Employee e);
}

Next, run the Web Services wizard to create a Web service from the JavaBean implementation and SEI. Let us also assume that we indicate to the Web Services wizard that it should generate the Java proxy classes to provide a client-side interface to the Web service. The wizard creates all the appropriate deployment descriptors and binding files. Finally, in the newly created Web services client project, we add a simple test class:

public class EmployeeTester {
	public static void main(String[] args) {
		try {
			java.rmi.Remote stub = createProxy();
			EmployeeFactory simpleWSTest = (EmployeeFactory)stub;
			SalariedEmployee fred = new SalariedEmployee();
			fred.setName("Fred");
			fred.setSalary(1000);
			System.out.println("-------Salaried Test---------");
			System.out.println(simpleWSTest.deriveInfoFor(fred));
			System.out.println("-------Regular Test----------");
			Employee bob = new Employee();
			bob.setName("Bob");
			System.out.println(simpleWSTest.deriveInfoFor(bob));
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	private static java.rmi.Remote createProxy() throws ServiceException {
		return 
		(java.rmi.Remote) (new EmployeeFactoryServiceLocator().getPort(EmployeeFactory.class));
	}
}

However, when we run this test, we do not get the outcome we expect. Instead of seeing that Fred is a SalariedEmployee and Bob is a regular Employee, the information returned indicates that both Fred and Bob are regular Employees. In other words, the extended information is not being passed to the Web service. If you turn on the TCP/IP monitor in WebSphere Studio Application Developer (hereafter called Application Developer), you will see that the salary information is never passed to the server.

If you look inside the WSDL that was generated, you will quickly see why this example does not work: the extension tags described above are never generated. The reason, quite simply, is that the code generators that build the WSDL and the associated Serializer and Deserializer objects for the value types do not know that they need to deal specifically with the subclass, since only the superclass is directly referenced in the SEI.

Java2WSDL, which is the WebSphere Application Server 5.02 tool that actually does the work of generating the WSDL "under the covers" in Application Developer, can actually handle this case. You need to explicitly provide the extensions to Java2WSDL so it maps them into the WSDL file. You can do this using the -extraClasses option. For example:

Java2WSDL EmployeeFactoryIF -extraClasses SalariedEmployee

This feature of Java2WSDL, however, has not yet been exposed in the Application Developer tooling. Therefore, the solution to making argument inheritance work in Application Developer 5.1 is that you have to include a method on your Web service that includes every one of the subclasses of the base class to get the Java2WSDL tool to include the appropriate schema extensions in the WSDL file. In our example, we can do this by adding a method of the following form to both the Service Endpoint Interface and to the JavaBean Web service implementation class:

public void dummy(SalariedEmployee e)

After adding this method and re-running the Web Services wizard, the WSDL is generated correctly. You can then use the base class, or any of the subclasses, in methods that are typed to expect the base class as a method argument. The following WSDL types declaration shows how the correct WSDL should look in our example after adding the "dummy" methods.

wsdl:types>
  <schema elementFormDefault="qualified" 
  targetNamespace="http://lukas.ws.demo.ibm.com" 
  xmlns="http://www.w3.org/2001/XMLSchema">
   <complexType name="Employee">
    <sequence>
     <element name="name" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
   <element name="deriveInfoFor">
    <complexType>
     <sequence>
      <element name="e" nillable="true" type="impl:Employee"/>
     </sequence>	
    </complexType>
   </element>
   <element name="deriveInfoForResponse">
    <complexType>
     <sequence>
      <element name="deriveInfoForReturn" nillable="true" type="xsd:string"/>
     </sequence>
    </complexType>
   </element>
   <complexType name="SalariedEmployee">
    <complexContent>
     <extension base="impl:Employee">
      <sequence>
       <element name="salary" type="xsd:int"/>
      </sequence>
     </extension>
    </complexContent>
   </complexType>
   <element name="dummy">
    <complexType>
     <sequence>
      <element name="e" nillable="true" type="impl:SalariedEmployee"/>
     </sequence>
    </complexType>
   </element>
  </schema>
 </wsdl:types>

At this point, re-running the test described previously results in the correct result:

----------Salaried Test---------
Name=Fred Person is a SalariedEmployee 1000
----------Regular Test----------
Name=Bob Person is a Regular Employee

Results of testing interoperability against .NET

After having tested that value type inheritance works correctly in the JAX-RPC implementation in WebSphere Application Server V5.02 and WebSphere Studio Application Developer Version 5.1, we needed to determine whether or not the WSDL that was generated would be compatible with .NET. Andrew Spyker, from the WebSphere performance team, took the complete set of WSDL that was so generated and generated Client proxies for C# within Microsoft Visual Studio. The relevant segment of this code is shown below:

public class Employee {
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public string name;
    }
    /// <remarks/>
    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://lukas.ws.demo.ibm.com")]
    public class SalariedEmployee : Employee {
        /// <remarks/>
        public int salary;
    }

In this example, Visual Studio .NET interpreted the WSDL in the same way as JAX-RPC; that is, as value object inheritance. After writing a simple C# .NET client program roughly equivalent to the one shown in Java above, we observed that the .NET client generated the appropriate SOAP messages for representing requests to the service:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<deriveInfoFor xmlns="http://lukas.ws.demo.ibm.com">
<e xsi:type="SalariedEmployee">
<name>Hello World</name>
<salary>10</salary>
</e>
</deriveInfoFor>
</soap:Body>
</soap:Envelope>

Thus, in this simple example, we found that a C# client could interoperate with the Java server in the expected way given only the information in the generated WSDL.


Recommendations: Designing for SOA

Despite the positive outcome of our interoperability experiment with Microsoft Visual Studio and the .NET framework, my fear is that this approach will not be broadly portable. The basic reason for this concern is that the use of the extension mechanism for value object inheritance is outside of the WS-I basic profile, although not specifically excluded by it. Currently, there is no mention of using the extension construct in the WS-I basic profile and, additionally, the WS-I compliance test suite does not cover this case. Therefore, it is logical to conclude that this aspect of interoperability has not been formally tested as part of WS-I compliance.

The goal of the WS-I basic profile has been to identify those areas of Web services that caused the most problems in interoperability scenarios, and to limit future problems by firmly deciding each debated point. This is a learning process, however, and even though the WS-I basic profile is now in the fully approved 1.0 state, interoperability issues are still being discovered.

Yet another consideration is that we are dealing with value types (or to use the now commonly accepted term, "Data Transfer Objects"). To quote from Martin Fowler's pithy description of these objects:

"In many ways, a Data Transfer Object is one of those objects our mothers told us never to write. A Data Transfer Object is often little more than a bunch of fields and getters and setters for these fields. The value of this usually hateful beast is that it allows you to move several pieces of information over a network in a single call - a trick that is essential for distributed systems."
(from Patterns of Enterprise Application Architecture, p 427)

The key thing to realize here is that these "hateful beasts" exist for one purpose and one purpose only: to move data from one place to another. Object inheritance is best applied to behavior, not data (see [Auer] for a lucid argument on this point). The ability to inherit behavior is at the heart of most common design patterns. However, given the specialized nature of Data Transfer Objects, there is usually no behavior for them to inherit. As such, inheritance is of minimal utility at best.


Conclusion

Even though we have been able to demonstrate a measure of interoperability in using the inheritance approach for value types, I would recommend caution in taking this approach. Given that the WS-I specification is silent on the issue, that it requires extra work within WebSphere to make the approach work, and that the benefits gained through such an approach are minimal, the risk of running into interoperability issues down the road seems to outweigh the potential benefits to be gained.

Resources

  • [Auer] Ken Auer, "Reusability Through Self-Encapsulation", originally published in Pattern Languages of Program Design, Addison-Wesley, Reading, MA, 1994, available at: http://www.rolemodelsoftware.com/moreAboutUs/publications/articles/self-enc.php
  • [Fowler] Martin Fowler, Patterns of Enterprise Application Architecture, Addison-Wesley, Reading, MA, 2002
  • [WSDL12] W3C, The Web Services Definition Language Specification, version 1.2 http://www.w3.org/TR/wsdl12/

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
ArticleID=14461
ArticleTitle=IBM WebSphere Developer Technical Journal: Web Services Value Type Inheritance and Interoperability
publish-date=01192004