@Beta public abstract class TypeToken<T> extends TypeCapture<T> implements java.io.Serializable
Type
with generics.
Operations that are otherwise only available in Class
are implemented to support
Type
, for example isSubtypeOf(com.google.common.reflect.TypeToken<?>)
, isArray()
and getComponentType()
.
It also provides additional utilities such as getTypes()
, resolveType(java.lang.reflect.Type)
, etc.
There are three ways to get a TypeToken
instance:
Type
obtained via reflection. For example: TypeToken.of(method.getGenericReturnType())
.
new TypeToken<List<String>>() {}
Note that it's critical that the actual type argument is carried by a subclass. The
following code is wrong because it only captures the <T>
type variable of the
listType()
method signature; while <String>
is lost in erasure:
class Util {
static <T> TypeToken<List<T>> listType() {
return new TypeToken<List<T>>() {};
}
}
TypeToken<List<String>> stringListType = Util.<String>listType();
abstract class IKnowMyType<T> {
TypeToken<T> type = new TypeToken<T>(getClass()) {};
}
new IKnowMyType<String>() {}.type => String
TypeToken
is serializable when no type variable is contained in the type.
Note to Guice users: TypeToken is similar to Guice's TypeLiteral
class except
that it is serializable and offers numerous additional utility methods.
Modifier and Type | Class and Description |
---|---|
private static class |
TypeToken.Bounds |
private class |
TypeToken.ClassSet |
private class |
TypeToken.InterfaceSet |
private static class |
TypeToken.SimpleTypeToken<T> |
private static class |
TypeToken.TypeCollector<K>
Collects parent types from a sub type.
|
private static class |
TypeToken.TypeFilter |
class |
TypeToken.TypeSet
The set of interfaces and classes that
T is or is a subtype of. |
Modifier and Type | Field and Description |
---|---|
private TypeResolver |
covariantTypeResolver
Resolver for resolving covariant types with
runtimeType as context. |
private TypeResolver |
invariantTypeResolver
Resolver for resolving parameter and field types with
runtimeType as context. |
private java.lang.reflect.Type |
runtimeType |
private static long |
serialVersionUID |
Modifier | Constructor and Description |
---|---|
protected |
TypeToken()
Constructs a new type token of
T . |
protected |
TypeToken(java.lang.Class<?> declaringClass)
Constructs a new type token of
T while resolving free type variables in the context of
declaringClass . |
private |
TypeToken(java.lang.reflect.Type type) |
Modifier and Type | Method and Description |
---|---|
private static TypeToken.Bounds |
any(java.lang.reflect.Type[] bounds) |
private TypeToken<? super T> |
boundAsSuperclass(java.lang.reflect.Type bound) |
private ImmutableList<TypeToken<? super T>> |
boundsAsInterfaces(java.lang.reflect.Type[] bounds) |
private static java.lang.reflect.Type |
canonicalizeTypeArg(java.lang.reflect.TypeVariable<?> declaration,
java.lang.reflect.Type typeArg)
In reflection,
Foo<?>.getUpperBounds()[0] is always Object.class , even when Foo
is defined as Foo<T extends String> . |
private static java.lang.reflect.ParameterizedType |
canonicalizeWildcardsInParameterizedType(java.lang.reflect.ParameterizedType type) |
private static java.lang.reflect.Type |
canonicalizeWildcardsInType(java.lang.reflect.Type type) |
private static java.lang.reflect.WildcardType |
canonicalizeWildcardType(java.lang.reflect.TypeVariable<?> declaration,
java.lang.reflect.WildcardType type) |
Invokable<T,T> |
constructor(java.lang.reflect.Constructor<?> constructor)
|
boolean |
equals(java.lang.Object o)
Returns true if
o is another TypeToken that represents the same Type . |
private static TypeToken.Bounds |
every(java.lang.reflect.Type[] bounds) |
private TypeToken<? extends T> |
getArraySubtype(java.lang.Class<?> subclass) |
private TypeToken<? super T> |
getArraySupertype(java.lang.Class<? super T> supertype) |
TypeToken<?> |
getComponentType()
Returns the array component type if this type represents an array (
int[] , T[] ,
<? extends Map<String, Integer>[]> etc.), or else null is returned. |
private TypeResolver |
getCovariantTypeResolver() |
(package private) ImmutableList<TypeToken<? super T>> |
getGenericInterfaces()
Returns the generic interfaces that this type directly
implements . |
(package private) TypeToken<? super T> |
getGenericSuperclass()
Returns the generic superclass of this type or
null if the type represents Object or an interface. |
private TypeResolver |
getInvariantTypeResolver() |
private java.lang.reflect.Type |
getOwnerTypeIfPresent()
Returns the owner type of a
ParameterizedType or enclosing class of a Class , or
null otherwise. |
java.lang.Class<? super T> |
getRawType()
Returns the raw type of
T . |
private ImmutableSet<java.lang.Class<? super T>> |
getRawTypes() |
TypeToken<? extends T> |
getSubtype(java.lang.Class<?> subclass)
Returns subtype of
this with subclass as the raw class. |
private TypeToken<? extends T> |
getSubtypeFromLowerBounds(java.lang.Class<?> subclass,
java.lang.reflect.Type[] lowerBounds) |
TypeToken<? super T> |
getSupertype(java.lang.Class<? super T> superclass)
Returns the generic form of
superclass . |
private TypeToken<? super T> |
getSupertypeFromUpperBounds(java.lang.Class<? super T> supertype,
java.lang.reflect.Type[] upperBounds) |
java.lang.reflect.Type |
getType()
Returns the represented type.
|
TypeToken.TypeSet |
getTypes()
Returns the set of interfaces and classes that this type is or is a subtype of.
|
int |
hashCode() |
private boolean |
is(java.lang.reflect.Type formalType,
java.lang.reflect.TypeVariable<?> declaration)
A.is(B) is defined as Foo<A>.isSubtypeOf(Foo<B>) . |
boolean |
isArray()
Returns true if this type is known to be an array type, such as
int[] , T[] ,
<? extends Map<String, Integer>[]> etc. |
private boolean |
isOwnedBySubtypeOf(java.lang.reflect.Type supertype) |
boolean |
isPrimitive()
Returns true if this type is one of the nine primitive types (including
void ). |
boolean |
isSubtypeOf(java.lang.reflect.Type supertype)
Returns true if this type is a subtype of the given
type . |
boolean |
isSubtypeOf(TypeToken<?> type)
Returns true if this type is a subtype of the given
type . |
private boolean |
isSubtypeOfArrayType(java.lang.reflect.GenericArrayType supertype) |
private boolean |
isSubtypeOfParameterizedType(java.lang.reflect.ParameterizedType supertype) |
boolean |
isSupertypeOf(java.lang.reflect.Type type)
Returns true if this type is a supertype of the given
type . |
boolean |
isSupertypeOf(TypeToken<?> type)
Returns true if this type is a supertype of the given
type . |
private boolean |
isSupertypeOfArray(java.lang.reflect.GenericArrayType subtype) |
private boolean |
isWrapper() |
Invokable<T,java.lang.Object> |
method(java.lang.reflect.Method method)
|
private static java.lang.reflect.Type |
newArrayClassOrGenericArrayType(java.lang.reflect.Type componentType)
Creates an array class if
componentType is a class, or else, a GenericArrayType . |
static <T> TypeToken<T> |
of(java.lang.Class<T> type)
Returns an instance of type token that wraps
type . |
static TypeToken<?> |
of(java.lang.reflect.Type type)
Returns an instance of type token that wraps
type . |
(package private) TypeToken<T> |
rejectTypeVariables()
Ensures that this type token doesn't contain type variables, which can cause unchecked type
errors for callers like
TypeToInstanceMap . |
private TypeToken<?> |
resolveSupertype(java.lang.reflect.Type type) |
TypeToken<?> |
resolveType(java.lang.reflect.Type type)
Resolves the given
type against the type context represented by this type. |
private java.lang.reflect.Type |
resolveTypeArgsForSubclass(java.lang.Class<?> subclass) |
private boolean |
someRawTypeIsSubclassOf(java.lang.Class<?> superclass) |
(package private) static <T> TypeToken<? extends T> |
toGenericType(java.lang.Class<T> cls)
Returns the type token representing the generic type declaration of
cls . |
java.lang.String |
toString() |
TypeToken<T> |
unwrap()
Returns the corresponding primitive type if this is a wrapper type; otherwise returns
this itself. |
<X> TypeToken<T> |
where(TypeParameter<X> typeParam,
java.lang.Class<X> typeArg)
Returns a new
TypeToken where type variables represented by typeParam are
substituted by typeArg . |
<X> TypeToken<T> |
where(TypeParameter<X> typeParam,
TypeToken<X> typeArg)
Returns a new
TypeToken where type variables represented by typeParam are
substituted by typeArg . |
TypeToken<T> |
wrap()
Returns the corresponding wrapper type if this is a primitive type; otherwise returns
this itself. |
protected java.lang.Object |
writeReplace()
Implemented to support serialization of subclasses.
|
capture
private final java.lang.reflect.Type runtimeType
private transient TypeResolver invariantTypeResolver
runtimeType
as context.private transient TypeResolver covariantTypeResolver
runtimeType
as context.private static final long serialVersionUID
protected TypeToken()
T
.
Clients create an empty anonymous subclass. Doing so embeds the type parameter in the anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
For example:
TypeToken<List<String>> t = new TypeToken<List<String>>() {};
protected TypeToken(java.lang.Class<?> declaringClass)
T
while resolving free type variables in the context of
declaringClass
.
Clients create an empty anonymous subclass. Doing so embeds the type parameter in the anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
For example:
abstract class IKnowMyType<T> {
TypeToken<T> getMyType() {
return new TypeToken<T>(getClass()) {};
}
}
new IKnowMyType<String>() {}.getMyType() => String
private TypeToken(java.lang.reflect.Type type)
public static <T> TypeToken<T> of(java.lang.Class<T> type)
type
.public static TypeToken<?> of(java.lang.reflect.Type type)
type
.public final java.lang.Class<? super T> getRawType()
T
. Formally speaking, if T
is returned by Method.getGenericReturnType()
, the raw type is what's returned by Method.getReturnType()
of the same method object. Specifically:
T
is a Class
itself, T
itself is returned.
T
is a ParameterizedType
, the raw type of the parameterized type is
returned.
T
is a GenericArrayType
, the returned type is the corresponding array
class. For example: List<Integer>[] => List[]
.
T
is a type variable or a wildcard type, the raw type of the first upper bound
is returned. For example: <X extends Foo> => Foo
.
public final java.lang.reflect.Type getType()
public final <X> TypeToken<T> where(TypeParameter<X> typeParam, TypeToken<X> typeArg)
TypeToken
where type variables represented by typeParam
are
substituted by typeArg
. For example, it can be used to construct Map<K, V>
for
any K
and V
type:
static <K, V> TypeToken<Map<K, V>> mapOf(
TypeToken<K> keyType, TypeToken<V> valueType) {
return new TypeToken<Map<K, V>>() {}
.where(new TypeParameter<K>() {}, keyType)
.where(new TypeParameter<V>() {}, valueType);
}
X
- The parameter typetypeParam
- the parameter type variabletypeArg
- the actual type to substitutepublic final <X> TypeToken<T> where(TypeParameter<X> typeParam, java.lang.Class<X> typeArg)
TypeToken
where type variables represented by typeParam
are
substituted by typeArg
. For example, it can be used to construct Map<K, V>
for
any K
and V
type:
static <K, V> TypeToken<Map<K, V>> mapOf(
Class<K> keyType, Class<V> valueType) {
return new TypeToken<Map<K, V>>() {}
.where(new TypeParameter<K>() {}, keyType)
.where(new TypeParameter<V>() {}, valueType);
}
X
- The parameter typetypeParam
- the parameter type variabletypeArg
- the actual type to substitutepublic final TypeToken<?> resolveType(java.lang.reflect.Type type)
type
against the type context represented by this type. For example:
new TypeToken<List<String>>() {}.resolveType(
List.class.getMethod("get", int.class).getGenericReturnType())
=> String.class
private TypeToken<?> resolveSupertype(java.lang.reflect.Type type)
final TypeToken<? super T> getGenericSuperclass()
null
if the type represents Object
or an interface. This method is similar but different from Class.getGenericSuperclass()
. For example, new TypeToken<StringArrayList>()
{}.getGenericSuperclass()
will return new TypeToken<ArrayList<String>>() {}
; while
StringArrayList.class.getGenericSuperclass()
will return ArrayList<E>
, where
E
is the type variable declared by class ArrayList
.
If this type is a type variable or wildcard, its first upper bound is examined and returned if the bound is a class or extends from a class. This means that the returned type could be a type variable too.
final ImmutableList<TypeToken<? super T>> getGenericInterfaces()
implements
. This method is
similar but different from Class.getGenericInterfaces()
. For example, new
TypeToken<List<String>>() {}.getGenericInterfaces()
will return a list that contains new TypeToken<Iterable<String>>() {}
; while List.class.getGenericInterfaces()
will
return an array that contains Iterable<T>
, where the T
is the type variable
declared by interface Iterable
.
If this type is a type variable or wildcard, its upper bounds are examined and those that are either an interface or upper-bounded only by interfaces are returned. This means that the returned types could include type variables too.
private ImmutableList<TypeToken<? super T>> boundsAsInterfaces(java.lang.reflect.Type[] bounds)
public final TypeToken.TypeSet getTypes()
Subtypes are always listed before supertypes. But the reverse is not true. A type isn't necessarily a subtype of all the types following. Order between types without subtype relationship is arbitrary and not guaranteed.
If this type is a type variable or wildcard, upper bounds that are themselves type variables aren't included (their super interfaces and superclasses are).
public final TypeToken<? super T> getSupertype(java.lang.Class<? super T> superclass)
superclass
. For example, if this is ArrayList<String>
, Iterable<String>
is returned given the input Iterable.class
.public final TypeToken<? extends T> getSubtype(java.lang.Class<?> subclass)
this
with subclass
as the raw class. For example, if this is
Iterable<String>
and subclass
is List
, List<String>
is
returned.public final boolean isSupertypeOf(TypeToken<?> type)
type
. "Supertype" is defined
according to the rules for type
arguments introduced with Java generics.public final boolean isSupertypeOf(java.lang.reflect.Type type)
type
. "Supertype" is defined
according to the rules for type
arguments introduced with Java generics.public final boolean isSubtypeOf(TypeToken<?> type)
type
. "Subtype" is defined
according to the rules for type
arguments introduced with Java generics.public final boolean isSubtypeOf(java.lang.reflect.Type supertype)
type
. "Subtype" is defined
according to the rules for type
arguments introduced with Java generics.public final boolean isArray()
int[]
, T[]
,
<? extends Map<String, Integer>[]>
etc.public final boolean isPrimitive()
void
).public final TypeToken<T> wrap()
this
itself. Idempotent.private boolean isWrapper()
public final TypeToken<T> unwrap()
this
itself. Idempotent.public final TypeToken<?> getComponentType()
int[]
, T[]
,
<? extends Map<String, Integer>[]>
etc.), or else null
is returned.public final Invokable<T,java.lang.Object> method(java.lang.reflect.Method method)
public final Invokable<T,T> constructor(java.lang.reflect.Constructor<?> constructor)
public boolean equals(java.lang.Object o)
o
is another TypeToken
that represents the same Type
.equals
in class java.lang.Object
public int hashCode()
hashCode
in class java.lang.Object
public java.lang.String toString()
toString
in class java.lang.Object
protected java.lang.Object writeReplace()
final TypeToken<T> rejectTypeVariables()
TypeToInstanceMap
.private boolean someRawTypeIsSubclassOf(java.lang.Class<?> superclass)
private boolean isSubtypeOfParameterizedType(java.lang.reflect.ParameterizedType supertype)
private boolean isSubtypeOfArrayType(java.lang.reflect.GenericArrayType supertype)
private boolean isSupertypeOfArray(java.lang.reflect.GenericArrayType subtype)
private boolean is(java.lang.reflect.Type formalType, java.lang.reflect.TypeVariable<?> declaration)
A.is(B)
is defined as Foo<A>.isSubtypeOf(Foo<B>)
.
Specifically, returns true if any of the following conditions is met:
formalType
are equal.
formalType
have equal canonical form.
formalType
is <? extends Foo>
and 'this' is a subtype of Foo
.
formalType
is <? super Foo>
and 'this' is a supertype of Foo
.
Enum<? extends Enum<E>>
canonicalizes to
Enum<?>
where E
is the type variable declared on the Enum
class
declaration. It's technically not true that Foo<Enum<? extends Enum<E>>>
is a
subtype of Foo<Enum<?>>
according to JLS. See testRecursiveWildcardSubtypeBug() for
a real example.
It appears that properly handling recursive type bounds in the presence of implicit type bounds is not easy. For now we punt, hoping that this defect should rarely cause issues in real code.
formalType
- is Foo<formalType>
a supertype of Foo<T>
?declaration
- The type variable in the context of a parameterized type. Used to infer
type bound when formalType
is a wildcard with implicit upper bound.private static java.lang.reflect.Type canonicalizeTypeArg(java.lang.reflect.TypeVariable<?> declaration, java.lang.reflect.Type typeArg)
Foo<?>.getUpperBounds()[0]
is always Object.class
, even when Foo
is defined as Foo<T extends String>
. Thus directly calling <?>.is(String.class)
will return false. To mitigate, we canonicalize wildcards by enforcing the following
invariants:
canonicalize(t)
always produces the equal result for equivalent types. For example
both Enum<?>
and Enum<? extends Enum<?>>
canonicalize to
Enum<? extends Enum<E>
.
canonicalize(t)
produces a "literal" supertype of t.
For example: Enum<? extends Enum<?>>
canonicalizes to Enum<?>
, which is
a supertype (if we disregard the upper bound is implicitly an Enum too).
canonicalize(A) == canonicalize(B)
, then Foo<A>.isSubtypeOf(Foo<B>)
and
vice versa. i.e. A.is(B)
and B.is(A)
.
canonicalize(canonicalize(A)) == canonicalize(A)
.
private static java.lang.reflect.Type canonicalizeWildcardsInType(java.lang.reflect.Type type)
private static java.lang.reflect.WildcardType canonicalizeWildcardType(java.lang.reflect.TypeVariable<?> declaration, java.lang.reflect.WildcardType type)
private static java.lang.reflect.ParameterizedType canonicalizeWildcardsInParameterizedType(java.lang.reflect.ParameterizedType type)
private static TypeToken.Bounds every(java.lang.reflect.Type[] bounds)
private static TypeToken.Bounds any(java.lang.reflect.Type[] bounds)
private ImmutableSet<java.lang.Class<? super T>> getRawTypes()
private boolean isOwnedBySubtypeOf(java.lang.reflect.Type supertype)
private java.lang.reflect.Type getOwnerTypeIfPresent()
ParameterizedType
or enclosing class of a Class
, or
null otherwise.static <T> TypeToken<? extends T> toGenericType(java.lang.Class<T> cls)
cls
. For example:
TypeToken.getGenericType(Iterable.class)
returns Iterable<T>
.
If cls
isn't parameterized and isn't a generic array, the type token of the class is
returned.
private TypeResolver getCovariantTypeResolver()
private TypeResolver getInvariantTypeResolver()
private TypeToken<? super T> getSupertypeFromUpperBounds(java.lang.Class<? super T> supertype, java.lang.reflect.Type[] upperBounds)
private TypeToken<? extends T> getSubtypeFromLowerBounds(java.lang.Class<?> subclass, java.lang.reflect.Type[] lowerBounds)
private TypeToken<? super T> getArraySupertype(java.lang.Class<? super T> supertype)
private java.lang.reflect.Type resolveTypeArgsForSubclass(java.lang.Class<?> subclass)
private static java.lang.reflect.Type newArrayClassOrGenericArrayType(java.lang.reflect.Type componentType)
componentType
is a class, or else, a GenericArrayType
. This is what Java7 does for generic array type parameters.