Summary
Neil Gafter has proposed Super Type Tokens and also noted their limitations. Alternatives include reify generics and providing generic factories. Super Type Tokens are a means of remembering the erased type using a token, which is an instance of TypeRef in the example.

Advertisement

Super Type Tokens

Neil Gafter has proposed Super
Type Tokens and also noted their limitations.
Alternatives include
reify
generics and providing generic factories. Super
Type Tokens are a means of remembering the erased type using a token, which is
an instance of TypeRef in the example. Neil gives an example of its use:

The code for TypeRef is a little obscure and the Javadoc for Type etc. are
of no use! Since TypeRef is generic and abstract the supertype of an instance
of type TypeRef must be generic and hence the cast to ParameterizedType won't
fail (line 10). One you have a ParameterizedType you can ask for its type parmeters,
in this case it has one. Now you can use an instance of TypeRef as a genric
token because its equals and hashCode methods look at the generic type.

The usage example is a store of favourites that are accessed via generic type
tokens. However the cast on line 32 that is ignored (line 30) circumvents the
type checking and if two layers of generics are used, e.g. a generic list
is the generic parameter to TypeRef, it fails, as shown below.

The problem is that when the token is created (line 10) for both List<String>
(line 20) and List<Integer> (line 21) the same token is created, one
for a java.util.List<T>, in both cases. Thus the call to favoriteList
on both lines 20 and 21 returns the same list and therefore when run you get
a type error when you attempt the read this list as a String (line 23), because
you have already put an Integer in (line 22). The type system did detect a
potential problem but the warning was supressed and hence a runtime error.

One solution is to reify generics,
i.e.“erase
erasure”, this is my prefered option, via adding a source statement
so that backward compatibility isn't broken. A source statment identifies the
version of Java in use, e.g. source 7;, states that it is Java 7. This way generics
can be reified in 7 and erased in pre-7. Note the idea of a source statement
was my suggestion.

The code is straightforward to anyone familiar with the factory design pattern.
Factories are typically singletons and in this case an enum is used to make
a singleton factory. A feature of using a factory instead of a token is that
you would not have an expectation that something made by a different factory
was the same sort of object even if the structural type of the object was the
same. I.E. two List<String> would be different types if made by different
factories, i.e. no structural matching of types just matching based on factories.
The resulting example of using favorites that cause a problem before is now
OK:

The above code works as expected because the factories are singletons and
are therefore passed to favoriteList rather than being new objects with an
erased second level type. As noted above the TypeRef version
in both cases is of type List<T>, whereas with the factories the types are
List< String > and List< Integer >.

In the case of Neil's example neither the
type token nor the factory are used for anything other than undoing the effects
of erasure. However both techniques can do much more, in particular they
can make instances of generic objects.

In the above example a shadow collection set of interfaces called collectionPlus, in the example, is added that has extra methods that are correctly typed and which return the factory which can be used as a type token. The abstract collections are modified to have a factory field and to have constructors that accept factories and to implement the plus interfaces.