Grrr. I really wish Java had either:
- Reified generics or
- Closures
In the interim, I offer the following Java code to the world. Does it help? Use at your own risk.
This is a class that wraps the collections interface to provide for recovery of the type parameter. To use it, make a new instance and pass the class object for the parameter to the constructor, along with the original collection.
package gypsum.util; import java.util.Collection; import java.util.Iterator; /** * This class packages some implementation of {@link Collection} along with * the class object for the type parameter of the collection. This allows * getting the type of objects in the collection using the {@link #getType()} * method, and then using the resulting class to perform casts. This basically * creates a "reified" generic collection (of sorts). * * @param Class of data held in this collection. * @author sprowell * @version $Revision$ $Date$ */ public class TypedCollection implements Collection { private Class type; private Collection implementation; /** * Make a new instance. * @param type The class object for the type of elements. * @param implementation The implementation. */ public TypedCollection(Class type, Collection implementation) { if (type == null) { throw new NullPointerException("The type is null."); } if (implementation == null) { throw new NullPointerException("The implementation is null."); } this.type = type; this.implementation = implementation; } /** * Get the type held in this collection. * @return The type held in this collection. */ public Class getType() { return type; } /** * Recover the original typed collection. In order for this to work, * the correct class must be supplied; otherwise you will get a * {@link ClassCastException}. Use this as follows. * <pre> * TypedCollection<Foo> coll = oldcoll.recover(oldcoll.getType()); * * * This converts from {@code TypedCollection<?>} to * {@code TypedCollection&ltT>}, so you recover the generic type * parameter. * * This may seem backward, or even a little contrived. Blame it on * the Java generics system. The reason you must pass the class * object <em>in</em>, even though it is maintained here, is that * the compiler must know the type of the object <em>at the point * you use this method</em>. Thus you can do the following. * <pre> * public void print(TypedCollection<?> coll) { * if (coll.getType() == String.class) { * TypedCollection<String> coll = coll.recover(String.class); * for (String str : coll) { * System.out.println(str); * } * } * } * </pre> * * @param The type of the desired collection. * @param kind The class object for type T. * @return The correctly cast generic collection. * @throws ClassCastException * This instance is <em>not</em> the type desired. */ @SuppressWarnings("unchecked") public TypedCollection recover(Class kind) { if (kind == type) { return (TypedCollection) this; } throw new ClassCastException("Incorrect cast."); } /** * {@inheritDoc} * @see java.util.Collection#add(java.lang.Object) */ @Override public boolean add(E arg) { return implementation.add(arg); } /** * {@inheritDoc} * @see java.util.Collection#addAll(java.util.Collection) */ @Override public boolean addAll(Collection arg) { return implementation.addAll(arg); } /** * {@inheritDoc} * @see java.util.Collection#clear() */ @Override public void clear() { implementation.clear(); } /** * {@inheritDoc} * @see java.util.Collection#contains(java.lang.Object) */ @Override public boolean contains(Object arg) { return implementation.contains(arg); } /** * {@inheritDoc} * @see java.util.Collection#containsAll(java.util.Collection) */ @Override public boolean containsAll(Collection c) { return implementation.containsAll(c); } /** * {@inheritDoc} * @see java.util.Collection#isEmpty() */ @Override public boolean isEmpty() { return implementation.isEmpty(); } /** * {@inheritDoc} * @see java.util.Collection#iterator() */ @Override public Iterator iterator() { return implementation.iterator(); } /** * {@inheritDoc} * @see java.util.Collection#remove(java.lang.Object) */ @Override public boolean remove(Object o) { return implementation.remove(o); } /** * {@inheritDoc} * @see java.util.Collection#removeAll(java.util.Collection) */ @Override public boolean removeAll(Collection c) { return implementation.removeAll(c); } /** * {@inheritDoc} * @see java.util.Collection#retainAll(java.util.Collection) */ @Override public boolean retainAll(Collection c) { return implementation.retainAll(c); } /** * {@inheritDoc} * @see java.util.Collection#size() */ @Override public int size() { return implementation.size(); } /** * {@inheritDoc} * @see java.util.Collection#toArray() */ @Override public Object[] toArray() { return implementation.toArray(); } /** * {@inheritDoc} * @see java.util.Collection#toArray(T[]) */ @Override public T[] toArray(T[] a) { return implementation.toArray(a); } }

See java.util.Collections.checkedCollection. It’s been there since Java 5.
The checkedCollection() doesn’t seem to give me what I want; specifically, the recover(Class) method. That is, I have a method that must take a Collection<?>, but I really want a Collection<Foo> or Collection<Bar>. I can check the type and then use recover(Foo.class) or recover(Bar.class).
Collection<Foo> fooColl = coll.recover(Foo.class);
I’m then free to pass this on to methods that require the correct type.
Doesn’t work for nested generics, but nothing really does. I believe this is one of Java’s weakest points.