Evaluating Software Design Patterns
— the "Gang of Four" patterns implemented in Java 6

dk.rode.thesis.meta.reflect
Class TypeLiteral<T>

java.lang.Object
  extended by dk.rode.thesis.meta.reflect.TypeLiteral<T>
Type Parameters:
T - The type represented by this type literal.
Direct Known Subclasses:
InstantiableTypeLiteral

public abstract class TypeLiteral<T>
extends Object

Represents the type realised as the type parameter T, where T may be a generic type that need not be reifiable.

The type of T can be retrieved with the getType() method. It can represent a class, a type variable, a wild-card type, a component type of a generic type array, or a type parameter of a parameterised type with a single type parameter (also called a component type).

The raw type of T can be retrieved with the getRawType() method if T does not represent a type variable, a wild-card, or a generic array type storing type variables.

A type literal can also represent non-reifiable types. Hence, there can be inconsistencies between T and the actual type represented by the literal because of erasure: though T may seem to represent a known type in the literal, say Integer as in TypeLiteral<Integer>, the actual type can represent a type variable, say S, as is illustrated in the examples below (see for example literal5). This is normally not an issue if type literals are created explicitly and not by generic methods or through extended inheritance.

Examples:

 
 // Standard creation...
  
 // T = Integer, type = class, raw type = Integer class
 TypeLiteral<Integer> literal1 = new TypeLiteral<Integer>(){};
 
 // T = Object[], type = generic array type, raw type = Object class
 TypeLiteral<Object[]> literal2 = new TypeLiteral<Object[]>(){};
 
 // T = Class<String>[], type = generic array type, raw type = Class class
 TypeLiteral<Class<String>[]> literal3 = new TypeLiteral<Class<String>[]>(){};
 
 // T = List<?>, type = class, raw type = List interface
 TypeLiteral<List<?>> literal4 = new TypeLiteral<List<?>>(){};
 
 // Factory creation...
 
 // Generic factory methods...
 public static <S> TypeLiteral<S> create1(S value) {
   return new TypeLiteral<S>(){};
 }
 public static <R> TypeLiteral<Comparable<R>> create2(R value) {
     return new TypeLiteral<Comparable<R>(){};
 }
 
 // Potential trouble: T = Integer, type = type variable (S), raw type = null
 TypeLiteral<Integer> literal5 = create1(new Integer(1));
 
 // Potential trouble: T = Class<Integer>, type = type variable (S), raw type = null
 TypeLiteral<Class<Integer>> literal6 = create1(Integer.class);

 // Potential trouble: T = Class<Integer>, type = type variable (S), raw type = null 
 TypeLiteral<Class<Integer>> literal7 = create1(null);
    
 // Potential trouble: T = Comparable<Long>, 
 //                        type = parameterised type (with type parameter R), raw type = Comparable interface
 TypeLiteral<Comparable<Long>> literal8 = create2(Long.class);
 
 // Potential trouble: T = Comparable<Object>, 
 //                        type = parameterised type (with type parameter R), raw type = Comparable interface
 TypeLiteral<Comparable<Object>> literal9 = create2(null);
 
 // Inheritance...
 
 class Foo extends TypeLiteral<ArrayList<?>>{};
 class FooFoo extends TypeLiteral<CharSequence>{};
 class Bar extends Foo {};
 class Goo<K,V> extends TypeLiteral<Map<K,V>>{};
 class FooGoo<K,V> extends TypeLiteral<Map<Long,Void>>{};
 class FooBar extends Goo<String,Void> {};

 // T = ArrayList<?>, type = parameterised type, raw type = ArrayList class 
 Foo literal10 = new Foo();
 
 // T = CharSequence, type = class, raw type = CharSequence interface 
 FooFoo literal11 = new FooFoo();
 
 // Potential trouble: T = Map<K,V>, type = parameterised type, raw type = Map interface 
 Goo literal12 = new Goo<String,Integer>();
 
 // T = Map<Long,Void>, type = parameterised type, raw type = Map interface
 FooGoo literal13 = new FooGoo<String,Integer>();
 
 // Throws illegal argument exception: Bar has no immediate generic super type 
 Bar literal14 = new Bar();

 // Potential trouble: FooBar's immediate generic super type has two type parameters: 
 // <String,Void>, and so the first, e.g. String, is used.
 FooBar literal15 = new FooBar();
 
Implementation notes:
Based on Gafter's Gadget, an idea by Neal Gafter [Gafter06].

See [Langer06], for example technical details FAQ106, for an easily understandable discussion on reifiable types and erasure. It contains condensed information from The Java Language Specification, Third Edition [Gosling05] about reifiable types.

Author:
Gunni Rode / rode.dk
See Also:
getComponentType(Type), getRawType(Type), InstantiableTypeLiteral

Field Summary
protected  Type type
          The actual Type object representing the type realised as the type parameter T.
 
Constructor Summary
protected TypeLiteral()
          Constructor, which creates this type literal to represent the type represented by the type parameter T.
private TypeLiteral(Type type)
          Constructor, which creates this type literal to represent the component type of the type supplied as type.
  TypeLiteral(TypeLiteral<T> typeLiteral)
          Copy constructor, which creates this type literal based on the type represented by typeLiteral.
 
Method Summary
 Class<T> asClass()
          Returns a view of the type represented by this type literal as a class literal if and only if the type has a raw type.
 Class<T> asClass(Class<?> clazz)
          Returns a view of the class represented by clazz as the type represented by this type literal, if possible.
<S> TypeLiteral<T>
asType(TypeLiteral<S> typeLiteral)
          Returns a view of typeLiteral as the type represented by this type literal, T instead of S, if possible.
static
<S> TypeLiteral<?>
create(Class<S> clazz)
          Returns a type literal representing the generic super-type of class supplied as clazz.
static TypeLiteral<?> create(Object object)
          Returns a type literal representing the generic super-type of class of object.
static TypeLiteral<?> create(Type type)
          Returns a type literal representing the component type supplied via type.
 boolean equals(Object object)
          Returns true of object is a type literal representing the same type as this type literal, false if not.
static Type getComponentType(Type type)
          Returns the component type of the type supplied as type if a parameterised type or generic array type, otherwise type itself.
 Class<?> getRawType()
          Returns the raw type represented by this type literal, if any.
static Class<?> getRawType(Type type)
          Returns the raw type represented by the type supplied as type, if any.
 Type getType()
          Returns the type represented by this type literal.
 int hashCode()
          Return the hash code of this type literal.
private static boolean isAssignableFrom(Type a, Type b, boolean equal)
          Returns true if a is recursively assignable from b, false if not.
 String toString()
          Returns the string representation of this type literal.
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

type

protected final Type type
The actual Type object representing the type realised as the type parameter T.

Never null.

Constructor Detail

TypeLiteral

protected TypeLiteral()
Constructor, which creates this type literal to represent the type represented by the type parameter T.

Throws:
IllegalArgumentException - If this class is not generic.

TypeLiteral

private TypeLiteral(Type type)
Constructor, which creates this type literal to represent the component type of the type supplied as type.

Parameters:
type - The type; cannot be null.
Throws:
NullPointerException - If type is null.
IllegalArgumentException - If type is a parameterised type with no type parameter (if more than one, the first is used). Zero type parameters can occur if type type represents a non-parameterised type nested within a parameterised type.
See Also:
getComponentType(Type)

TypeLiteral

public TypeLiteral(TypeLiteral<T> typeLiteral)
Copy constructor, which creates this type literal based on the type represented by typeLiteral.

Parameters:
typeLiteral - The type literal to copy; cannot be null.
Throws:
NullPointerException - If typeLiteral is null.
Method Detail

asClass

public Class<T> asClass()
Returns a view of the type represented by this type literal as a class literal if and only if the type has a raw type.

Note, that if the type is generic, the returned class literal actually represents the raw type!

Returns:
A class literal, or null.
See Also:
asClass(Class), asType(TypeLiteral)

asClass

public Class<T> asClass(Class<?> clazz)
Returns a view of the class represented by clazz as the type represented by this type literal, if possible.

This type must have a raw type for this method to have a chance of succeeding.

Note, that if the type is generic, the returned class literal actually represents the raw type!

Parameters:
clazz - The class to view as the type represented by this type literal; cannot be null.
Returns:
A class literal; never null.
Throws:
NullPointerException - If clazz is null.
ClassCastException - If clazz cannot be viewed as the type represented by this type literal.
See Also:
asClass(), asType(TypeLiteral)

asType

public <S> TypeLiteral<T> asType(TypeLiteral<S> typeLiteral)
Returns a view of typeLiteral as the type represented by this type literal, T instead of S, if possible.

If a cast from S to T is not possible, a class cast exception is thrown. If the type represented by this type literal does not have a raw type, a class cast exception will also be thrown. Two will card types will cause a class cast exception, as a simple cast will suffice.

The test for matching types is done recursively, including test for generic array and parameter types with bounded and/or unbounded wild-cards.

Type Parameters:
S - The type represented by typeLiteral.
Parameters:
typeLiteral - The type literal; cannot be null.
Returns:
typeLiteral casted to represent T instead of S, if possible; never null.
Throws:
NullPointerException - If typeLiteral is null.
IllegalArgumentException - If either T or S recursively do not represent a parameterised type.
ClassCastException - If typeLiteral cannot represent T.
See Also:
getComponentType(Type), asClass(), asClass(Class)

create

public static <S> TypeLiteral<?> create(Class<S> clazz)
Returns a type literal representing the generic super-type of class supplied as clazz.

Type Parameters:
S - The type of clazz.
Parameters:
clazz - The class literal representing the type; cannot be null.
Returns:
A type literal representing the generic super-type; never null.
Throws:
NullPointerException - If clazz is null.
See Also:
create(Type)

create

public static TypeLiteral<?> create(Object object)
Returns a type literal representing the generic super-type of class of object.

Parameters:
object - The object to supply the class; cannot be null.
Returns:
A type literal representing the generic super-type of the class of object; never null.
Throws:
NullPointerException - If object is null.

create

public static TypeLiteral<?> create(Type type)
Returns a type literal representing the component type supplied via type.

Parameters:
type - The type; cannot be null.
Returns:
A type literal representing the component type of type; never null.
Throws:
NullPointerException - If type is null.
See Also:
getComponentType(Type), create(Class)

equals

public boolean equals(Object object)
Returns true of object is a type literal representing the same type as this type literal, false if not.

Overrides:
equals in class Object
Parameters:
object - The object to test; can be null.
Returns:
True if equal, false if not.

getComponentType

public static Type getComponentType(Type type)
Returns the component type of the type supplied as type if a parameterised type or generic array type, otherwise type itself.

If there are more than one parameter types, the first one is used, and the additional ones ignored.

The component type may be a generic type.

Parameters:
type - The type to supply the component type, if any; cannot be null.
Returns:
The (component) type; never null.
Throws:
NullPointerException - If type is null.
IllegalArgumentException - If type is a parameterised type with no type parameters (if more than one, the first one is used). Zero type parameters can occur if type type represents a non-parameterised type nested within a parameterised type.

getRawType

public Class<?> getRawType()
Returns the raw type represented by this type literal, if any.

A raw type cannot be returned if this type literal represents a type variable, a wild-card, or a generic array type storing type variables.

The raw type may be the same as getType().

Returns:
The raw type or null.
See Also:
getRawType(Type)

getRawType

public static Class<?> getRawType(Type type)
Returns the raw type represented by the type supplied as type, if any.

A raw type cannot be returned if type is a type variable, a wild card, or a generic array type storing type variables.

Parameters:
type - The type to use; cannot be null.
Returns:
The raw type or null.
Throws:
NullPointerException - If type is null.

getType

public Type getType()
Returns the type represented by this type literal.

Returns:
The type; never null.
See Also:
getComponentType(Type)

hashCode

public int hashCode()
Return the hash code of this type literal.

Overrides:
hashCode in class Object
Returns:
The hash code.

isAssignableFrom

private static final boolean isAssignableFrom(Type a,
                                              Type b,
                                              boolean equal)
Returns true if a is recursively assignable from b, false if not.

The test will always returns false if either a or b are a type variable. For generic array and parameterised types, the test will recurse. Wild cards bounds are handled as well.

Two unbounded wild card types will return false!

Parameters:
a - The first type; cannot be null.
b - The second type; cannot be null.
equal - True if a class match is determined using equals(Object) instead of isAssignableFrom(Class).
Returns:
True if a is recursively assignable from b, false if not.
See Also:
getComponentType(Type)

toString

public String toString()
Returns the string representation of this type literal.

Overrides:
toString in class Object
Returns:
The string representation; never null.

Gunni Rode / rode.dk

Feel free to use and/or modify the Java 6 source code developed for this thesis AT YOUR OWN RISK, but note that the source code comes WITHOUT ANY — and I do mean WITHOUT ANY — form of warranty WHAT SO EVER!

The original thesis and source code are available at rode.dk/thesis.