Optimizing Web Services Using Java, Part I
Generic Java and Web services
Source Code for this article
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.
About the Author
Jordan Anastasiade is a professor of computer studies at
Seneca College at York University, Toronto campus. He has
created industry-leading software products architecting and
developing distributed applications. Currently, he is teaching
Java technology and Web services.
jordan.anastasiade@senecac.on.ca
Optimizing Web Services Using Java, Part I by Jordan Anastasiade
WSJ Vol 03 Issue 12 - pg.51
Listing 1: Web service implementation – generates runtime error
Object[] objectArray = new Integer[1];
objectArray[0] = "zero"; //throws exception at run-time
Listing 2: Company class hierarchy implementation
public abstract class Employee {
public abstract int salaryFrom(Company c);
}
public class Sales extends Employee {
...
public int salaryFrom(Company c){ ...}
...
}
public class Programmer extends Employee {
...
public int salaryFrom(Company c){ ...}
...
}
public class Student extends Employee {
private List<CoopStudent> coopStudents;
public int salaryFrom(Company c){ ...}
...
}
public class Company {
int salary = 0;
public void daySalary(Employee e) {
salary += e.salaryFrom(this);
}
}
Listing 3: Department salary web service implementation
public void
departmentSalary(List<Employee> employees) {
for (Employee e: employees)
salary += e.salaryFrom(this);
}
Listing 4: Error writing to a covariant type
List<Student> students =
new LinkedList<Student>();
List<? extends Employee> employees = students;
employees.add(0, new GeneralManager()); // error
Listing 5: Using covariant generic type as factory
public class HummanResources {
private Factory<? extends Employee> factory;
public void
setFactory(Factory<? extends Employee> f) {
factory = f;
}
/* Generates a new employee object */
public void newEmployee() {
Employee e = factory.create();
...
}
}
Listing 6: Using covariant and contravariant generic type
void move(List<? super Employee> to,
List<? extends Employee> from);
Listing 7: Using contravariant generic type as comparator
public interface Comparator<T> {
int compare(T x, T y);
}
public static <T>
T theBest(List<T> e, Comparator<? super T> c);
Listing 8: Using bivariant generic type
public int
all(List<? extends List<?>> departments) {
int total = 0;
for (List<?> department : departments) {
total += department.size();
}
return total;
}
All Rights Reserved
Copyright © 2004 SYS-CON Media, Inc.
E-mail:
info@sys-con.com