Saturday, January 03, 2009

You're not my type? Super Type Tokens to Rescue!

Ok, so accessing real type information regading Java Generic classes and methods is problematic as per my previous blog entry.

All possible workarounds listed require creating dummy classes (3 mentioned, plus one I forgot about, that of class member/static variables); but the most promising approach is probably that of using sub-classing. The first thought I had was to perhaps require sub-classing the specific class or interface and providing type information that way. For example, to specify type "HashMap<String,String>", you would define a class like:

  public class MyDummyMap extends HashMap<String,String> { }

And then pass "MyDummyMap.class" as the type argument to whatever methods needs this type information. This would work in many cases; for abstract classes and interfaces you could just define class as abstract. After all, we don't need instances of the class, just the class to provide type information for the "Real Type" we want.

However while this does allow functionality, it is not optimal from robustness perspective: after all, type of the argument itself is just Class<?>. Further, caller has to know the class has to sub-class something, and provide full generic typing. It sure would be nice to have more descriptive type for the argument; as well as some static (and if need be, dynamic) error checking to ensure that type information is properly passed.

This is where "Super Type Tokens" (courtesy of Java Guru mr. Gafter) comes in -- and I'm glad I happened to find it when googling for solutions to the problem. The idea is obvious once you know it: instead of sub-classing the parametrized class, define an abstract reference class and sub-class that reference (which, then, is statically typed and explicitly known to be a form of type reference). It allows for ensuring that typing is provided, and with some additional tricks (such as a reader's suggestion of making TypeReference implement a dummy interface such as Comparable) can be explicit, easy-to-understand, concise and reliable way to pass exact type information.

Even better, implementation from these ideas is quite simple.

A possible implementation is as follows (this one adapted from Jackson codebase):


public abstract class TypeReference<T>
  implements Comparable<TypeReference<T>>
{
 final java.lang.reflect.Type _type;

 protected TypeReference()
 {
  java.lang.reflect.Type superClass = getClass().getGenericSuperclass();
  _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
 }

 public Type getType() { return _type; }

 // We define this method (and require implementation of Comparable
 // to prevent constructing a reference without type information.
 public int compareTo(TypeReference<T> o) {
  return 0; // dummy, never used
 }
}

And usage would be like:

Decoder d = DecoderFactory.forTypeReference(new TypeReference<HashMap<String,String>>() { } );

which seems clear enough -- even if ideally Java language would have explicit support for proper type information passing.

The only minor annoyance I have left with this is the profileration of these disposable dummy classes, only purpose of which is to contain little bit of type information. But I'll take this solution over not having any. :-)

blog comments powered by Disqus

Sponsored By


Related Blogs

(by Author (topics))

Powered By

About me

  • I am known as Cowtowncoder
  • Contact me at@yahoo.com
Check my profile to learn more.