Package net.jodah.typetools
Class TypeResolver
- java.lang.Object
-
- net.jodah.typetools.TypeResolver
-
public final class TypeResolver extends java.lang.Object
Enhanced type resolution utilities.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static interface
TypeResolver.AccessMaker
static class
TypeResolver.Unknown
An unknown type.
-
Field Summary
Fields Modifier and Type Field Description private static boolean
CACHE_ENABLED
private static java.lang.reflect.Method
GET_CONSTANT_POOL
private static java.lang.reflect.Method
GET_CONSTANT_POOL_METHOD_AT
private static java.lang.reflect.Method
GET_CONSTANT_POOL_SIZE
private static java.lang.Object
JAVA_LANG_ACCESS
private static java.lang.Double
JAVA_VERSION
private static java.util.Map<java.lang.String,java.lang.reflect.Method>
OBJECT_METHODS
private static java.util.Map<java.lang.Class<?>,java.lang.Class<?>>
PRIMITIVE_WRAPPERS
private static boolean
RESOLVES_LAMBDAS
private static java.util.Map<java.lang.Class<?>,java.lang.ref.Reference<java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type>>>
TYPE_VARIABLE_CACHE
Cache of type variable/argument pairs
-
Constructor Summary
Constructors Modifier Constructor Description private
TypeResolver()
-
Method Summary
All Methods Static Methods Concrete Methods Modifier and Type Method Description static void
disableCache()
Disables the internal caching of resolved TypeVariables.static void
enableCache()
Enables the internal caching of resolved TypeVariables.private static java.lang.reflect.Member
getConstantPoolMethodAt(java.lang.Object constantPool, int i)
private static int
getConstantPoolSize(java.lang.Object constantPool)
private static java.lang.reflect.Member
getMemberRef(java.lang.Class<?> type)
private static java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type>
getTypeVariableMap(java.lang.Class<?> targetType, java.lang.Class<?> functionalInterface)
private static boolean
isAutoBoxingMethod(java.lang.reflect.Method method)
private static boolean
isDefaultMethod(java.lang.reflect.Method m)
private static void
populateLambdaArgs(java.lang.Class<?> functionalInterface, java.lang.Class<?> lambdaType, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> map)
Populates themap
with variable/argument pairs for thefunctionalInterface
.private static void
populateSuperTypeArgs(java.lang.reflect.Type[] types, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> map, boolean depthFirst)
Populates themap
with with variable/argument pairs for the giventypes
.private static void
populateTypeArgs(java.lang.reflect.ParameterizedType type, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> map, boolean depthFirst)
Populates themap
with variable/argument pairs for the giventype
.static <T,S extends T>
java.lang.reflect.Typereify(java.lang.Class<T> type, java.lang.Class<S> context)
Traverses a generic type and replaces all type variables and wildcard types with concrete types (if possible), by using the type information from givencontext
.static java.lang.reflect.Type
reify(java.lang.reflect.Type type)
Traverses a generic type and replaces all type variables and wildcard types with concrete types (if possible).static java.lang.reflect.Type
reify(java.lang.reflect.Type type, java.lang.Class<?> context)
Traverses a generic type and replaces all type variables and wildcard types with concrete types (if possible), by using the type information from givencontext
.private static java.lang.reflect.Type
reify(java.lang.reflect.Type genericType, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> typeVariableTypeMap)
private static java.lang.reflect.Type
reify(java.lang.reflect.Type genericType, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> typeVariableMap, java.util.Map<java.lang.reflect.ParameterizedType,ReifiedParameterizedType> partial)
Works likeresolveRawClass(Type, Class, Class)
but does not stop at raw classes.static java.lang.reflect.Type
resolveBound(java.lang.reflect.TypeVariable<?> typeVariable)
Resolves the first bound for thetypeVariable
, returningUnknown.class
if none can be resolved.static java.lang.reflect.Type
resolveGenericType(java.lang.Class<?> type, java.lang.reflect.Type subType)
Returns the generictype
using type variable information from thesubType
elsenull
if the generic type cannot be resolved.static <T,S extends T>
java.lang.Class<?>resolveRawArgument(java.lang.Class<T> type, java.lang.Class<S> subType)
Returns the raw class representing the argument for thetype
using type variable information from thesubType
.static java.lang.Class<?>
resolveRawArgument(java.lang.reflect.Type genericType, java.lang.Class<?> subType)
Returns the raw class representing the argument for thegenericType
using type variable information from thesubType
.static <T,S extends T>
java.lang.Class<?>[]resolveRawArguments(java.lang.Class<T> type, java.lang.Class<S> subType)
Returns an array of raw classes representing arguments for thetype
using type variable information from thesubType
.static java.lang.Class<?>[]
resolveRawArguments(java.lang.reflect.Type genericType, java.lang.Class<?> subType)
Returns an array of raw classes representing arguments for thegenericType
using type variable information from thesubType
.static java.lang.Class<?>
resolveRawClass(java.lang.reflect.Type genericType, java.lang.Class<?> subType)
Resolves the raw class for thegenericType
, using the type variable information from thesubType
elseTypeResolver.Unknown
if the raw class cannot be resolved.private static java.lang.Class<?>
resolveRawClass(java.lang.reflect.Type genericType, java.lang.Class<?> subType, java.lang.Class<?> functionalInterface)
private static java.lang.Class<?>
wrapPrimitives(java.lang.Class<?> clazz)
-
-
-
Field Detail
-
TYPE_VARIABLE_CACHE
private static final java.util.Map<java.lang.Class<?>,java.lang.ref.Reference<java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type>>> TYPE_VARIABLE_CACHE
Cache of type variable/argument pairs
-
CACHE_ENABLED
private static volatile boolean CACHE_ENABLED
-
RESOLVES_LAMBDAS
private static boolean RESOLVES_LAMBDAS
-
JAVA_LANG_ACCESS
private static java.lang.Object JAVA_LANG_ACCESS
-
GET_CONSTANT_POOL
private static java.lang.reflect.Method GET_CONSTANT_POOL
-
GET_CONSTANT_POOL_SIZE
private static java.lang.reflect.Method GET_CONSTANT_POOL_SIZE
-
GET_CONSTANT_POOL_METHOD_AT
private static java.lang.reflect.Method GET_CONSTANT_POOL_METHOD_AT
-
OBJECT_METHODS
private static final java.util.Map<java.lang.String,java.lang.reflect.Method> OBJECT_METHODS
-
PRIMITIVE_WRAPPERS
private static final java.util.Map<java.lang.Class<?>,java.lang.Class<?>> PRIMITIVE_WRAPPERS
-
JAVA_VERSION
private static final java.lang.Double JAVA_VERSION
-
-
Method Detail
-
enableCache
public static void enableCache()
Enables the internal caching of resolved TypeVariables.
-
disableCache
public static void disableCache()
Disables the internal caching of resolved TypeVariables.
-
resolveRawArgument
public static <T,S extends T> java.lang.Class<?> resolveRawArgument(java.lang.Class<T> type, java.lang.Class<S> subType)
Returns the raw class representing the argument for thetype
using type variable information from thesubType
. If no arguments can be resolved thenUnknown.class
is returned.- Parameters:
type
- to resolve argument forsubType
- to extract type variable information from- Returns:
- argument for
type
elseTypeResolver.Unknown
.class if no type arguments are declared - Throws:
java.lang.IllegalArgumentException
- if more or less than one argument is resolved for thetype
-
resolveRawArgument
public static java.lang.Class<?> resolveRawArgument(java.lang.reflect.Type genericType, java.lang.Class<?> subType)
Returns the raw class representing the argument for thegenericType
using type variable information from thesubType
. IfgenericType
is an instance of class, thengenericType
is returned. If no arguments can be resolved thenUnknown.class
is returned.- Parameters:
genericType
- to resolve argument forsubType
- to extract type variable information from- Returns:
- argument for
genericType
elseTypeResolver.Unknown
.class if no type arguments are declared - Throws:
java.lang.IllegalArgumentException
- if more or less than one argument is resolved for thegenericType
-
resolveRawArguments
public static <T,S extends T> java.lang.Class<?>[] resolveRawArguments(java.lang.Class<T> type, java.lang.Class<S> subType)
Returns an array of raw classes representing arguments for thetype
using type variable information from thesubType
. Arguments fortype
that cannot be resolved are returned asUnknown.class
. If no arguments can be resolved thennull
is returned.- Parameters:
type
- to resolve arguments forsubType
- to extract type variable information from- Returns:
- array of raw classes representing arguments for the
type
elsenull
if no type arguments are declared
-
reify
public static <T,S extends T> java.lang.reflect.Type reify(java.lang.Class<T> type, java.lang.Class<S> context)
Traverses a generic type and replaces all type variables and wildcard types with concrete types (if possible), by using the type information from givencontext
. A convenience method which largely works the same asreify(Type, Class)
, but first resolves the generic type oftype
.- Parameters:
type
- the class whose generic type to traversecontext
- the class that serves as starting point to resolve replacements of type variables- Returns:
- a type that is structurally the same as
type
, except that type variables and wildcard types have been replaced with concrete types - Throws:
java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is not an instance of one of the following types:Class
,TypeVariable
,WildcardType
,ParameterizedType
,GenericArrayType
.java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is aWildcardType
that does not have exactly one upper bound, or does not have no lower bounds.java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is aGenericArrayType
whose generic component type cannot be reified to an instance ofClass
.
-
reify
public static java.lang.reflect.Type reify(java.lang.reflect.Type type, java.lang.Class<?> context)
Traverses a generic type and replaces all type variables and wildcard types with concrete types (if possible), by using the type information from givencontext
. Generic types used as input to this method are commonly obtained using reflection, e.g. viaField.getGenericType()
,Method.getGenericReturnType()
,Method.getGenericParameterTypes()
. Example:
Reifying the generic return type of the methodclass A<T> { public T something; public Optional<List<T>> compute() { ... } } class B extends A<Number> { public <? extends Collection<List<?>>> collect() { ... } }
compute
withB.class
ascontext
will yield the parameterized typeOptional<List<Number>>
. Note that not the raw type (Optional
is returned, but the input type is reified recursively. Reifying the generic type of the fieldsomething
withB.class
ascontext
will yieldNumber.class
. Note that type variables with no explicit upper bound are reified toObject
, andUnknown.class
is never returned.- Parameters:
type
- the generic type to traversecontext
- the class that serves as starting point to resolve replacements of type variables- Returns:
- a type that is structurally the same as
type
, except that type variables and wildcard types have been replaced with concrete types - Throws:
java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is not an instance of one of the following types:Class
,TypeVariable
,WildcardType
,ParameterizedType
,GenericArrayType
.java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is aWildcardType
that does not have exactly one upper bound, or does not have no lower bounds.java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is aGenericArrayType
whose generic component type cannot be reified to an instance ofClass
.
-
reify
public static java.lang.reflect.Type reify(java.lang.reflect.Type type)
Traverses a generic type and replaces all type variables and wildcard types with concrete types (if possible). A convenience wrapper aroundreify(Type, Class)
, for when no context is needed/available. Generic types used as input to this method are commonly obtained using reflection, e.g. viaField.getGenericType()
,Method.getGenericReturnType()
,Method.getGenericParameterTypes()
. Example:
Reifying the generic return type of the methodclass X { public List<? extends Collection<List<? extends Number>>> collectList() { ... } public Set<?> collectSet() { ... } }
collectList
will yield the parameterized typeList<Collection<List<Number>>>
. Reifying the generic return type of the methodcollectSet
will yield the parameterized typeSet<Object>
, since there is no explicit upper bound for the wildcard type given.- Parameters:
type
- the generic type to traverse- Returns:
- a type that is structurally the same as
type
, except that type variables and wildcard types have been replaced with concrete types - Throws:
java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is not an instance of one of the following types:Class
,TypeVariable
,WildcardType
,ParameterizedType
,GenericArrayType
.java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is aWildcardType
that does not have exactly one upper bound, or does not have no lower bounds.java.lang.UnsupportedOperationException
- iftype
(or a type that it references) is aGenericArrayType
whose generic component type cannot be reified to an instance ofClass
.
-
resolveRawArguments
public static java.lang.Class<?>[] resolveRawArguments(java.lang.reflect.Type genericType, java.lang.Class<?> subType)
Returns an array of raw classes representing arguments for thegenericType
using type variable information from thesubType
. Arguments forgenericType
that cannot be resolved are returned asUnknown.class
. If no arguments can be resolved thennull
is returned.- Parameters:
genericType
- to resolve arguments forsubType
- to extract type variable information from- Returns:
- array of raw classes representing arguments for the
genericType
elsenull
if no type arguments are declared
-
resolveGenericType
public static java.lang.reflect.Type resolveGenericType(java.lang.Class<?> type, java.lang.reflect.Type subType)
Returns the generictype
using type variable information from thesubType
elsenull
if the generic type cannot be resolved.- Parameters:
type
- to resolve generic type forsubType
- to extract type variable information from- Returns:
- generic
type
elsenull
if it cannot be resolved
-
resolveRawClass
public static java.lang.Class<?> resolveRawClass(java.lang.reflect.Type genericType, java.lang.Class<?> subType)
Resolves the raw class for thegenericType
, using the type variable information from thesubType
elseTypeResolver.Unknown
if the raw class cannot be resolved.- Parameters:
genericType
- to resolve raw class forsubType
- to extract type variable information from- Returns:
- raw class for the
genericType
elseTypeResolver.Unknown
if it cannot be resolved
-
resolveRawClass
private static java.lang.Class<?> resolveRawClass(java.lang.reflect.Type genericType, java.lang.Class<?> subType, java.lang.Class<?> functionalInterface)
-
reify
private static java.lang.reflect.Type reify(java.lang.reflect.Type genericType, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> typeVariableTypeMap)
-
reify
private static java.lang.reflect.Type reify(java.lang.reflect.Type genericType, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> typeVariableMap, java.util.Map<java.lang.reflect.ParameterizedType,ReifiedParameterizedType> partial)
Works likeresolveRawClass(Type, Class, Class)
but does not stop at raw classes. Instead, traverses referenced types.- Parameters:
partial
- contains a mapping of generic types to reified types. A value ofnull
inside aReifiedParameterizedType
instance means that this type is currently being reified.
-
getTypeVariableMap
private static java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> getTypeVariableMap(java.lang.Class<?> targetType, java.lang.Class<?> functionalInterface)
-
populateSuperTypeArgs
private static void populateSuperTypeArgs(java.lang.reflect.Type[] types, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> map, boolean depthFirst)
Populates themap
with with variable/argument pairs for the giventypes
.
-
populateTypeArgs
private static void populateTypeArgs(java.lang.reflect.ParameterizedType type, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> map, boolean depthFirst)
Populates themap
with variable/argument pairs for the giventype
.
-
resolveBound
public static java.lang.reflect.Type resolveBound(java.lang.reflect.TypeVariable<?> typeVariable)
Resolves the first bound for thetypeVariable
, returningUnknown.class
if none can be resolved.
-
populateLambdaArgs
private static void populateLambdaArgs(java.lang.Class<?> functionalInterface, java.lang.Class<?> lambdaType, java.util.Map<java.lang.reflect.TypeVariable<?>,java.lang.reflect.Type> map)
Populates themap
with variable/argument pairs for thefunctionalInterface
.
-
isDefaultMethod
private static boolean isDefaultMethod(java.lang.reflect.Method m)
-
getMemberRef
private static java.lang.reflect.Member getMemberRef(java.lang.Class<?> type)
-
isAutoBoxingMethod
private static boolean isAutoBoxingMethod(java.lang.reflect.Method method)
-
wrapPrimitives
private static java.lang.Class<?> wrapPrimitives(java.lang.Class<?> clazz)
-
getConstantPoolSize
private static int getConstantPoolSize(java.lang.Object constantPool)
-
getConstantPoolMethodAt
private static java.lang.reflect.Member getConstantPoolMethodAt(java.lang.Object constantPool, int i)
-
-