Sunday, December 17, 2006
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]
Let's say I have a method to remotely execute some task. Its signature could be something like this:
But there is a catch, we would also like the argument to be Serializable. We could define an application specific interface like
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:
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.
"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:
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:
More goodies from Class class. Let's see how to dynamically load using generics. Again, we start with an example:
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:
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:
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:]
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]
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]
Subscribe to:
Posts (Atom)