Class TypeToken<T>

  • All Implemented Interfaces:
    java.io.Serializable
    Direct Known Subclasses:
    TypeToken.SimpleTypeToken

    public abstract class TypeToken<T>
    extends TypeCapture<T>
    implements java.io.Serializable
    A 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:

    • Wrap a Type obtained via reflection. For example: TypeToken.of(method.getGenericReturnType()).
    • Capture a generic type with a (usually anonymous) subclass. For example:
      
       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();
       
    • Capture a generic type with a (usually anonymous) subclass and resolve it against a context class that knows what the type parameters are. For example:
      
       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.

    Since:
    12.0
    See Also:
    Serialized Form
    • Field Detail

      • runtimeType

        private final java.lang.reflect.Type runtimeType
      • invariantTypeResolver

        private transient TypeResolver invariantTypeResolver
        Resolver for resolving parameter and field types with runtimeType as context.
      • covariantTypeResolver

        private transient TypeResolver covariantTypeResolver
        Resolver for resolving covariant types with runtimeType as context.
    • Constructor Detail

      • TypeToken

        protected TypeToken()
        Constructs a new type token of 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>>() {};
         
      • TypeToken

        protected TypeToken​(java.lang.Class<?> declaringClass)
        Constructs a new type token of 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
         
      • TypeToken

        private TypeToken​(java.lang.reflect.Type type)
    • Method Detail

      • of

        public static <T> TypeToken<T> of​(java.lang.Class<T> type)
        Returns an instance of type token that wraps type.
      • of

        public static TypeToken<?> of​(java.lang.reflect.Type type)
        Returns an instance of type token that wraps type.
      • getRawType

        public final java.lang.Class<? super T> getRawType()
        Returns the raw type of 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:
        • If T is a Class itself, T itself is returned.
        • If T is a ParameterizedType, the raw type of the parameterized type is returned.
        • If T is a GenericArrayType, the returned type is the corresponding array class. For example: List<Integer>[] => List[].
        • If 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.
      • getType

        public final java.lang.reflect.Type getType()
        Returns the represented type.
      • where

        public final <X> TypeToken<T> where​(TypeParameter<X> typeParam,
                                            TypeToken<X> typeArg)
        Returns a new 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);
         }
         
        Type Parameters:
        X - The parameter type
        Parameters:
        typeParam - the parameter type variable
        typeArg - the actual type to substitute
      • where

        public final <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. 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);
         }
         
        Type Parameters:
        X - The parameter type
        Parameters:
        typeParam - the parameter type variable
        typeArg - the actual type to substitute
      • resolveType

        public final TypeToken<?> resolveType​(java.lang.reflect.Type type)
        Resolves the given 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
         
      • resolveSupertype

        private TypeToken<?> resolveSupertype​(java.lang.reflect.Type type)
      • getGenericSuperclass

        final TypeToken<? super T> getGenericSuperclass()
        Returns the generic superclass of this type or 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.

      • boundAsSuperclass

        private TypeToken<? super T> boundAsSuperclass​(java.lang.reflect.Type bound)
      • getGenericInterfaces

        final ImmutableList<TypeToken<? super T>> getGenericInterfaces()
        Returns the generic interfaces that this type directly 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.

      • boundsAsInterfaces

        private ImmutableList<TypeToken<? super T>> boundsAsInterfaces​(java.lang.reflect.Type[] bounds)
      • getTypes

        public final TypeToken.TypeSet getTypes()
        Returns the set of interfaces and classes that this type is or is a subtype of. The returned types are parameterized with proper type arguments.

        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).

      • getSupertype

        public final TypeToken<? super T> getSupertype​(java.lang.Class<? super T> superclass)
        Returns the generic form of superclass. For example, if this is ArrayList<String>, Iterable<String> is returned given the input Iterable.class.
      • getSubtype

        public final TypeToken<? extends T> getSubtype​(java.lang.Class<?> subclass)
        Returns subtype of this with subclass as the raw class. For example, if this is Iterable<String> and subclass is List, List<String> is returned.
      • isSupertypeOf

        public final boolean isSupertypeOf​(TypeToken<?> type)
        Returns true if this type is a supertype of the given type. "Supertype" is defined according to the rules for type arguments introduced with Java generics.
        Since:
        19.0
      • isSupertypeOf

        public final boolean isSupertypeOf​(java.lang.reflect.Type type)
        Returns true if this type is a supertype of the given type. "Supertype" is defined according to the rules for type arguments introduced with Java generics.
        Since:
        19.0
      • isSubtypeOf

        public final boolean isSubtypeOf​(TypeToken<?> type)
        Returns true if this type is a subtype of the given type. "Subtype" is defined according to the rules for type arguments introduced with Java generics.
        Since:
        19.0
      • isSubtypeOf

        public final boolean isSubtypeOf​(java.lang.reflect.Type supertype)
        Returns true if this type is a subtype of the given type. "Subtype" is defined according to the rules for type arguments introduced with Java generics.
        Since:
        19.0
      • isArray

        public final boolean isArray()
        Returns true if this type is known to be an array type, such as int[], T[], <? extends Map<String, Integer>[]> etc.
      • isPrimitive

        public final boolean isPrimitive()
        Returns true if this type is one of the nine primitive types (including void).
        Since:
        15.0
      • wrap

        public final TypeToken<T> wrap()
        Returns the corresponding wrapper type if this is a primitive type; otherwise returns this itself. Idempotent.
        Since:
        15.0
      • isWrapper

        private boolean isWrapper()
      • unwrap

        public final TypeToken<T> unwrap()
        Returns the corresponding primitive type if this is a wrapper type; otherwise returns this itself. Idempotent.
        Since:
        15.0
      • getComponentType

        public final 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.
      • method

        public final Invokable<T,​java.lang.Object> method​(java.lang.reflect.Method method)
        Returns the Invokable for method, which must be a member of T.
        Since:
        14.0
      • constructor

        public final Invokable<T,​T> constructor​(java.lang.reflect.Constructor<?> constructor)
        Returns the Invokable for constructor, which must be a member of T.
        Since:
        14.0
      • equals

        public boolean equals​(java.lang.Object o)
        Returns true if o is another TypeToken that represents the same Type.
        Overrides:
        equals in class java.lang.Object
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class java.lang.Object
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object
      • writeReplace

        protected java.lang.Object writeReplace()
        Implemented to support serialization of subclasses.
      • rejectTypeVariables

        final TypeToken<T> rejectTypeVariables()
        Ensures that this type token doesn't contain type variables, which can cause unchecked type errors for callers like TypeToInstanceMap.
      • someRawTypeIsSubclassOf

        private boolean someRawTypeIsSubclassOf​(java.lang.Class<?> superclass)
      • isSubtypeOfParameterizedType

        private boolean isSubtypeOfParameterizedType​(java.lang.reflect.ParameterizedType supertype)
      • isSubtypeOfArrayType

        private boolean isSubtypeOfArrayType​(java.lang.reflect.GenericArrayType supertype)
      • isSupertypeOfArray

        private boolean isSupertypeOfArray​(java.lang.reflect.GenericArrayType subtype)
      • is

        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:

        1. 'this' and formalType are equal.
        2. 'this' and formalType have equal canonical form.
        3. formalType is <? extends Foo> and 'this' is a subtype of Foo.
        4. formalType is <? super Foo> and 'this' is a supertype of Foo.
        Note that condition 2 isn't technically accurate under the context of a recursively bounded type variables. For example, 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.

        Parameters:
        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.
      • canonicalizeTypeArg

        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>. Thus directly calling <?>.is(String.class) will return false. To mitigate, we canonicalize wildcards by enforcing the following invariants:
        1. canonicalize(t) always produces the equal result for equivalent types. For example both Enum<?> and Enum<? extends Enum<?>> canonicalize to Enum<? extends Enum<E>.
        2. 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).
        3. If canonicalize(A) == canonicalize(B), then Foo<A>.isSubtypeOf(Foo<B>) and vice versa. i.e. A.is(B) and B.is(A).
        4. canonicalize(canonicalize(A)) == canonicalize(A).
      • canonicalizeWildcardsInType

        private static java.lang.reflect.Type canonicalizeWildcardsInType​(java.lang.reflect.Type type)
      • canonicalizeWildcardType

        private static java.lang.reflect.WildcardType canonicalizeWildcardType​(java.lang.reflect.TypeVariable<?> declaration,
                                                                               java.lang.reflect.WildcardType type)
      • canonicalizeWildcardsInParameterizedType

        private static java.lang.reflect.ParameterizedType canonicalizeWildcardsInParameterizedType​(java.lang.reflect.ParameterizedType type)
      • every

        private static TypeToken.Bounds every​(java.lang.reflect.Type[] bounds)
      • any

        private static TypeToken.Bounds any​(java.lang.reflect.Type[] bounds)
      • getRawTypes

        private ImmutableSet<java.lang.Class<? super T>> getRawTypes()
      • isOwnedBySubtypeOf

        private boolean isOwnedBySubtypeOf​(java.lang.reflect.Type supertype)
      • getOwnerTypeIfPresent

        private java.lang.reflect.Type getOwnerTypeIfPresent()
        Returns the owner type of a ParameterizedType or enclosing class of a Class, or null otherwise.
      • toGenericType

        static <T> TypeToken<? extends T> toGenericType​(java.lang.Class<T> cls)
        Returns the type token representing the generic type declaration of 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.

      • getCovariantTypeResolver

        private TypeResolver getCovariantTypeResolver()
      • getInvariantTypeResolver

        private TypeResolver getInvariantTypeResolver()
      • getSupertypeFromUpperBounds

        private TypeToken<? super T> getSupertypeFromUpperBounds​(java.lang.Class<? super T> supertype,
                                                                 java.lang.reflect.Type[] upperBounds)
      • getSubtypeFromLowerBounds

        private TypeToken<? extends T> getSubtypeFromLowerBounds​(java.lang.Class<?> subclass,
                                                                 java.lang.reflect.Type[] lowerBounds)
      • getArraySupertype

        private TypeToken<? super T> getArraySupertype​(java.lang.Class<? super T> supertype)
      • getArraySubtype

        private TypeToken<? extends T> getArraySubtype​(java.lang.Class<?> subclass)
      • resolveTypeArgsForSubclass

        private java.lang.reflect.Type resolveTypeArgsForSubclass​(java.lang.Class<?> subclass)
      • newArrayClassOrGenericArrayType

        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. This is what Java7 does for generic array type parameters.