| By Jordan Anastasiade | Article Rating: |
|
| December 1, 2003 12:00 AM EST | Reads: |
16,109 |
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
Published December 1, 2003 Reads 16,109
Copyright © 2003 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Jordan Anastasiade
20+ years experience as programmer.
Professor teaching Web Service - Seneca College @ York University
------ Publications ------
Java Developer's Journal
- The Top 150 Players in Cloud Computing
- SYS-CON.TV: Cloud Computing Expo Power Panel
- Why IBM’s Server Chief Got Busted
- SOA World Power Panel on SYS-CON.TV
- 1st Annual GovIT Expo: Letter from the Technical Chair
- Deputy CIO of the CIA to Keynote 1st Annual GovIT Expo
- Stock in Focus: Dragon Capital
- 1st Annual Government IT Conference & Expo: Themes & Topics
- CIA was Headed to an Enterprise Cloud All Along: Jill Tummler Singer
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- The Top 150 Players in Cloud Computing
- SOA in the Cloud - Monitoring and Management for Reliability
- How to Diagnose Java Resource Starvation
- SYS-CON.TV: Cloud Computing Expo Power Panel
- Software AG Named "Gold Sponsor" of SOA World Conference & Expo 2009 East
- Why IBM’s Server Chief Got Busted
- IBM & Cloud Computing: How "SOA in the Cloud" Can Produce Real Change
- SYS-CON's Cloud Expo Adds Two New Tracks
- SOA World Power Panel on SYS-CON.TV
- 1st Annual GovIT Expo: Letter from the Technical Chair
- The i-Technology Right Stuff
- Who Are The All-Time Heroes of i-Technology?
- Get the Message
- Where Are RIA Technologies Headed in 2008?
- Success, Arrogance, Rise and Fall
- i-Technology Viewpoint: Is Web 2.0 the Global SOA?
- i-Technology Viewpoint: Thinking Outside the VC Box
- ESB Myth Busters: 10 Enterprise Service Bus Myths Debunked
- i-Technology Viewpoint: When to Leave Your First IT Job
- SOA Web Services Edge Conference Coverage on SYS-CON.TV









The new widgetry features multi-cluster suppo...

























