Welcome!

SOA & WOA Authors: Kevin Jackson, Maureen O'Gara, John Savageau, Greg Ness, Bruce Johnston

Related Topics: SOA & WOA

SOA & WOA: Article

Optimizing Web Services Using Java, Part I - Generic Java and Web services

Optimizing Web Services Using Java, Part I - Generic Java and Web services

What lies behind Web services? Some say the answer depends on the power of the language used in the implementation, in addition to known standards like XML, SOAP, and WSDL. Developing Web services is hard since incorrect use of the language can cause subtle and pernicious errors. What patterns and idioms should we use for simplifying the development process?

In this first of two articles, I describe some of the proposed changes to Java and show how they work together to make Java technology a more expressive language for Web services development. In a later article I'll use the Java Web Services Developer Pack (JWSDP 1.3), JAX-RPC 1.1 with its improved schema binding, and the architecture for Basic Profile 1.0, to demonstrate how to design Web services that perform well, how to identify idioms and patterns, and how to optimize Web services performance.

Generic Types
This article describes how generics will improve the design of Web services in Java. So what are generic types? Generics is basically a way to abstract over types. Practically, you can parameterize classes, interfaces, arrays, and methods. Take, for example, a well-known interface, List from java.util package, and try to rewrite it using a generic type T. A simplified version of a generic list interface would look like this:

interface List<T> {
void add(T x);
Iterator<T> iterator();
}

where T is type parameter being a reference to an object of any type from your List. Although the syntax may look similar, generics are not templates as in C++. Let's emphasize the advantages of generics. For instance, if you have a list of String objects you would probably write code like:

List firstList = new LinkedList();
firstList.add("something");String s =
(String)firstList.iterator.
next();

What's wrong with this code? Nothing. We've used it all the time as there were no other choices. However, someone working with your list could use it to pull an Integer object out of that list:

Integer i = (Integer)
firstList.iterator.next();

While the compiler will be happy, due to the cast operation the code will crash at runtime because your list contains only String objects. Wouldn't it be nice if you could tell the compiler what element type your list is? This is exactly what generics allows you to do:

List<String> secondList = new
LinkedList<String>();
secondList.add("something");
String s = secondList.iterator.next();

The generics code seems to be very similar to the previous code; in fact, you're dealing with the same idiom, but there is a big difference in the declaration of the generic variable. Now, with the generic code, the compiler could check that what you put in or what you pull out of the list is actually the type of object you declared your list to be. The collection List<String> allows only String objects. You could find more about generics and even use, today, a generic-capable compiler from the JSR-14 proposal.

What could we say about the relationship between a Collection of Integer and a Collection of Number where Collection<T> is a parameterized class in a type variable T? Mathematics demonstrates that Collection<Integer> is a subset of <Collection>Number while Integer is a subclass of Number class. How could we define a subtype relation between different instantiations of the same generic class?

Let C<T> be a parameterized class where T is a type variable, and A and B two classes, where B is a subclass of A. Is there a subtyping relationship between the two instantiations C<A> and C<B>? While the Programmer class is a subclass of the Employee class, we intuitively accept that List<Programmer > is a subclass of List<Employee >, but we cannot formally define such a relationship. More than that, if you want to declare a variable to hold, alternatively, both instances of List<Programmer > and List<Employee >, you have two options. The first option would be to use the raw type List obtained by the erasure of a parametric type T from the parameterized List<T> class. The second option would be to use a variable of type Object. Both solutions defeat the goals of genericity and the former may also result in unsafe code.

Furthermore, we could consider the Java array as a parameterized class with the type parameter being the type of the array. Between arrays there is already defined a subtyping relationship. For instance, Programmer[] is a subtype of Object[] because Programmer is a subtype of Object. Wouldn't it be nice if a Web service implementation (see Listing 1) never generated a run-time error? Could we define statically safe arrays, arrays that could be checked at compile time?

The solution is based on the notion of variance, which introduces a subtype relationship on the set of types defined by a parameterized class C<T>. The variant parameterized type is defined by replacing the type variable T with wildcards. Wildcards are useful where no specific knowledge about the type parameter is required. Thus, we can introduce the following definitions.

Covariance
A parameterized class C<T> is said to be covariant in the type parameter T, if for any classes A and B with B a subclass of A, the parameterized type C<B> is a subclass of the parameterized type C<A>
. The covariance annotation symbol is a wildcard with an explicit upper bound defined by the syntax

? extends T

where T is the bound. For example, the type

Vector<? extends Number>

is said to be covariant in Number and defines the subset of all instantiations of generic class Vector<T> where type variable T is at least of type Number. Covariant means that type variables and parameterized types vary in the same direction (covariance). The parameterized type List<? extends Employee > is a supertype of any parameterized type List<E> where Employee is a supertype of E and could be interpreted as all lists whose elements should be of al least type Employee. For instance, a parameterized type Vector<Integer> could be used when the parameterized type Vector<? extends Number> is needed:

Vector<? extends Number> vn =
new Vector<Integer>();

Contravariance:
A parameterized class C<T> is said to be contravariant in the type parameter T, if for any classes A and B with B a subclass of A, the parameterized type C<A> is a subclass of the parameterized type C<B>
. The contravariance annotation symbol is a wildcard with an explicit lower bound defined by the syntax:

? super T

where T is the bound. For instance, Vector<? super A> specializes Vector<? super B> if B specializes A, meaning that the type variables and parameterized types vary in the opposite directions (contra-variance). An Integer is a subtype of Number , whereas Vector<Number> is a subtype of Vector<? super Integer>. Thus, the parameterized type Vector<Number> could be used when the parameterized type Vector<? super Integer> is needed:

Vector<? super Integer> vi =
new Vector<Number>();

Bivariance
A parameterized class C<T> is said to be bivariant in the type parameter T, if C<T> is covariant and contravariant in T
. The wildcard ? is the bivariance annotation symbol. Vector<?> ranges over all instances of Vector<T> for any T. The wildcard in Vector<?> signifies that this could be a vector of anything. Thus, Vector<? super Integer> is a subtype of Vector<?> and Vector<? extends Integer> is a subtype of Vector<?>.

Invariance
A parameterized class C<T> is said to be invariant in the type parameter T, when C<A> is a subclass of C<B> if and only if A = B
. The invariant behavior imposes unnecessary limitations restricting the useful subtyping of generic types. Defining the concept of variance as a subtyping scheme for generic classes, we have introduced a new type of polymorphism called parametric polymorphism. Thus, for any generic class C<T> where T is a type parameter the following subtyping relationships hold true: C<T> is a subtype of C<? super T> which is a subtype of C<?>. The same goes true for covariant type: C<? extends T>.

Generally, variance of parametric types could be defined for any number of parameters. For instance, consider a parameterized class called Pair in type parameters U and V. The Vector covariant in Pair<U,V> could be:

Vector<? extends
Pair<?, ? super Integer>>

where the Pair is bivariant in the first element type "?" while the second element type is contravariant in the type parameter Integer.

Could the new variant scheme for generics be applied to any parameterized class? We will see in the next section that some constraints should be defined and applied to variant generic types for the soundness of our Web services design.

Applicability and Usefulness of Generic Types in Web Services Implementation
Consider a simple class hierarchy you define for a Web service implementation describing a company work force. You probably would design classes like employees for sales persons, programmers, managers, etc. (Listing 2). Let's suppose that you have to implement a Web service that calculates salary for a department of the company. You would probably organize the employees of that particular department as a list with a method departmentSalary() of Company class (see Listing 3). Let's suppose further that you want to calculate the salary of sales persons in that particular department using the generic method as defined in Listing 3. You cannot invoke the method with List<Sales> as list of sales persons because your method expects a List<Employee> although Sales is an Employee object. However, with variant generic types you can modify the method signature as follows: List<? extends Employee> meaning that any subclass of Employee class could be used as an actual type parameter. The modified method signature would be:

public void departmentSalary
(List<? extends Employee> employees);

There is still a problem. Suppose that your company accepts co-op students during the summer. You could create some temporary employees as a list of co-op students (see Listing 2). Now you can assign to an employees object the object students, because Student is a subclass of Employee class. If the snippet code in Listing 4 were allowed into your Web service implementation, the result would be that your GeneralManager would be stored in a list of students, as a temporary employee, causing headaches for you as a Web service developer. Had we allowed a write operation on a covariant generic type we would have compromised the integrity and consistency of our data structure and the safety and soundness of our Web services. To maintain the static type safety of generic code and to take advantage of the flexibility of variant generic type we have to restrict covariant generic type to read-only operations.

You might think that restricting the type of operation to a read-only one loses the expressiveness of a covariant generic type. For instance the idiom of creating objects using factory methods is well known. Consider a generic interface Factory<T> defined as:

public interface Factory<T> {
T create();
}

You might want to define a Web service for the human resources department that manages the company's employees. If you have written classes for the known types of employees:

public SalesFactory implements
Factory<Sales> {
public Sales create() {...}
}

you ought to design an easy-to-maintain Web service implementation that could be used for creating any type of employee, even types that are unknown at the time you write your first implementation as in Listing 6. You were able to design a covariant generic Factory<? extends Employee> type that can be used to create any kind of Employee objects. Listing 5 shows that you do not have to modify your implementation, even if your company hires a new employee for a job that did not exist at the time you wrote your Web service.

Suppose that you need a list of employees hired in the last month:

public void currentEmployees (List<?
super Employee> list, Employee e);

A contravariant generic type like List<? super Employee> is safe, since you put in your list objects of type Employee and the type parameter of List is being defined with ? super Employee as any supertype of Employee type . While the write operations are safe, we have to restrict the contravariant generic type to write-only operations.

Mixed variance parameterizations could be useful as well. Consider, for instance, a generic method that could be used to move the employees from one department to another (see Listing 6). Suppose now that you want to implement a Web service that finds out the best salesperson in your company. Probably you would define a generic Comparator<T> interface. Listing 7 uses a write-only contravariant generic Comparator<? super T> that would be able to compare any two objects. For instance, if you want to sort objects of type T you could define a sort method like:

public static <T extends Comparable<?
super T>> void sort(List<T> c);

On a bivariant generic class, neither read nor write operations are permitted. You may ask yourself where and how such a type could be useful as long as neither reading nor writing are allowed on such types. For example, based on a list of the departments and a list of all employees per department you want to calculate the total number of workers in your company (see Listing 8). The inner wildcard ? means that the inner List is a bivariant type. You don't use the list for reading out or for writing into, since the list as a bivariant type doesn't allow such operations. You only take the size of the list. The outer List with the type parameter: '? extends List<?>' defines a covariant type in List<?>. You use the read-only operation on the covariant outer List to discover the departments of your company.

Consider another example, with a class Pair<E, R>, where the first parameter defines an employee while the second defines a resource type. If your manager wants to have a list of all employees that need some vacation you can define a method with a signature like:

public <E> void employeesNeeds(List<?
extends Pair<? extends E, ?>> e);

The List is covariant in Pair<? extends E, ?> type, because it could be using any subtype of Pair<E, R> class. On the other hand Pair class is covariant in the first type parameter E, meaning that the first parameter of Pair<E, R> could be any employee type. The method does not read or write the particular type of resources, hence it is the bivariant annotation symbol "?" for the second parameter of Pair<E, R> class that defines resources.

Conclusion
We've examined the issues involved in supporting variant generic types in Java. A key aim in introducing genericity and variance to the Java programming language is the desire to write general, flexible, and complex Web services where decoupling and reuse are very important goals, while retaining and improving static type safety. Furthermore, variance annotations in class- and interface-type parameters increase the flexibility of subtyping relationships, allowing a better abstraction and maintainability and optimizing Web services as later articles will demonstrate.

Generics increases the readability, maintainability, and safety of our Web services and will be introduced in the next release of the Java programming language (J2SE 1.5 Tiger code name). That release will also include JSR-201 with enumerations, autoboxing for loop enhancements, import of static members, and metadata - features that are easy to use as neither syntax nor semantic restrictions have been imposed on the original language. My next article will demonstrate how to us the JWSDP 1.2, JAX-RPC 1.1 with generics and some of the new features that will make our Web services safer and easier to develop.

References

  • Bracha, Gilad; Odersky, Martin; Stoutamire, David; and Wadler, Philip. GJ Specification. Draft document, 1998. http://developer.java.sun.com/developer/ earlyAccess/adding_generics/index.html
  • Igarashi, Atsushi; and Viroli, Mirko. On Variance-based Subtyping for Parametric Types. ECOOP 2002
  • Joshua Bloch. (2000). Effective Java Programming Language Guide. Java Series, Sun Microsystems. ISBN 0-201-31005-8.
  • More Stories By Jordan Anastasiade

    20+ years experience as programmer.
    Professor teaching Web Service - Seneca College @ York University


    ------ Publications ------
    Java Developer's Journal

    Comments (0)

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.