Sunday, December 03, 2006

More Stupid Tiger Tricks

I'm trying to collect some idioms for programming with Java 5 generics, with varying degrees of usefulness, that I found scattered on different places. [Edit]Hopefully I fixed the whitespace problems on the code snippets. Blogger is pretty weak for working with source code, but now I believe its alright. As a bonus, I threw in another item on the end. I guess I'm all out of generic idioms for now.[/Edit]

Union Types


Let's say I have a method to remotely execute some task. Its signature could be something like this:

public void compute(Runnable task)

But there is a catch, we would also like the argument to be Serializable. We could define an application specific interface like

interface Task extends Runnable, Serializable {}

but that would prevent us from accepting exiting classes that just happened to implement both of these interfaces. Java 5 allows us to specify exactly that with union type bounds for type arguments. It is actually pretty easy, see how we apply the technique to our example:

public <T extends Runnable & Serializable> void compute(T task)

I advice you to reserve this idiom mostly for interacting with third-party code. If you find the need to require union types frequently on your own code, there is probably something wrong with the design and some refactoring may be in order.

Casting with a type token


"Know and use the libraries" is one of the most important items in Josh Bloch's Effective Java book. It's also one I frequently violate, only to regret later on. For instance, had I read class Class' documentation attentively, I could have avoided many unchecked cast warnings. An example is in order:

class Registry {
public void storeObject(Object obj) { }
public T getObject(Class<T> ofClass) {}
}

I think this class is pretty self explanatory, it can store an object indexed by it's class and later retrieve the stored instance. The challenge is how to implement it without upsetting the compiler. (And yes, @SupressWarnings("unchecked") is cheating...). For those of you who have done your homework and read class Class' javadocs you know this isn't much of a challenge after all, see:
   
class Registry {
private Map<Class<?>, Object> objects = new HashMap<Class<?>, Object>();

public void storeObject(Object obj) {
objects.put(obj.getClass(), obj);
}

public <T> T getObject(Class<T> ofClass) {
Object instance = objects.get(ofClass);
return ofClass.cast(instance);
}
}

Safe dynamic class loading


More goodies from Class class. Let's see how to dynamically load using generics. Again, we start with an example:

public interface ServiceLocator {
public Executor getExecutor();
}

This is a simple service locator that knows how to get an Executor instance. Service locators usually find service instances from naming services (in a Java EE environment, JNDI is most likely). But a simpler implementation could just read concrete class names from a properties file and instantiate the objects on construction. Let's take a shot at coding this up:

class ServiceLocatorProps implements ServiceLocator {
private Executor executor;

public ServiceLocatorProps() throws Exception {
Properties props = new Properties();
props.load(getClass().getResourceAsStream("services.properties"));

String executorClassName = props.getProperty(
"java.util.concurrent.Executor");

Class<Executor> executorClass =
(Class<Executor>) Class.forName(executorClassName);
//WARNING!!
this.executor = executorClass.newInstance();
}

public Executor getExecutor() {
return executor;
}

}


Please don't pay attention to the inexistent Exception handling. The point here is that the call to Class.forName() is followed by an unckecked cast and the compiler will promply warn us all about it. The correct code for this constructor would be:

public ServiceLocatorProps() throws Exception {
Properties props = new Properties();
props.load(getClass().getResourceAsStream("services.properties"));

String executorClassName = props.getProperty(
"java.util.concurrent.Executor");

Class<?> loadedClass = Class.forName(executorClassName);
Class<? extends Executor> executorClass = loadedClass.asSubclass(Executor.class);

this.executor = executorClass.newInstance();
}

Subclass to capture type arguments


This last one is not so much an idiom as a kludge to get around erasure. Most people who use generics in their code eventually get bitten by this problem, as I already bitched about before. Anyway, sometimes one way to get around the information loss is to subclass the parametrized type. This is because, unlike an instance of a generic type, a subclass does retain type argument information. For an example, see the problem recently posted by Ted Neward and my proposal for a "solution" (its the last one). A much more sophisticated example, including reflection, can be found on this Caelum blog post (it is in portuguese, but the code is understandable).
[Edit: one more item:]

Generic Wrapper


I guess I can't properly call this one an idiom, since I only saw it once. I'm talking about the java.sql.Wrapper interface in jdbc4. It is s a 2-method interface: isWrapperFor(Class<?> iface) and <T> T unwrap(Class<T> iface). It exists to expose extensions to a predefined API in a typesafe manner. I would serioulsy consider something like this when implementing a public extensible API/SPI.
[/Edit]

2 comments:

rahul said...
This comment has been removed by a blog administrator.
The Idioms said...

The Idiom: a way of talking that is normal to local speakers of a dialect

Each dialect has its own accumulation of astute colloquialisms. They offer counsel about how to live and furthermore exchange some hidden thoughts, standards and estimations of a given culture/society. These expressions are called "the idioms" - or maxims in the event that they are longer. These blends of words have (once in a while total sentences) a "metaphorical signifying" which means, they essentially work with "pictures".

Thanks
Freya, UK