public abstract class AbstractGenericsContext
extends java.lang.Object
GenericsContext, method context MethodGenericsContext or
constructor context ConstructorGenericsContext.
Note that all possible contexts extends from GenericsContext. AbstractGenericsContext
exists only to extract all core generics operations into separate class.
Usage: navigate to required type context.type(MyClass.class) and use utility methods to
get type's own generics or as helper for methods/fields introspection. To navigate to method context use
context.method(method).
Every context object is immutable. Navigation is allowed to any class (within original root class hierarchy) from any child context.
API operated mainly on types, because it's the only way to resolve recursive generics: e.g. when you have
List<Integer> then generic could be represented as Integer class, but if
List<Collection<Integer>> we can't represent generic as class (Collection),
because this makes actual collection generic not accessible)
Complete example: suppose we have class A extends B<Integer>.
GenericsResolver.resolve(A.class).type(B.class).generic(0) == Integer.class
It may be required to build context for some type, inside resolved hierarchy (e.g. for field). To do it
use inlyingType(Type) or inlyingTypeAs(Type, Class). Essentially, this is teh same as
building usual context, but with additional knowledge (extra generics, known on root type).
Another special case is inner classes, which could reference outer class generics. To handle this, outer class
generics are also resolved. For inlying context building, if outer class present in current (root) hierarchy,
then known outer class generics will be used from the root hierarchy. Also, not that outer class generics could be
declared directly (e.g. field declaration: Outer<String>.Inner field) and, in this case, direct
declaration is used in priority.
It is impossible to to perform incorrect generics resolution through context api: it will either change context automatically or fail with error (with detailed incompatibility explanation).
| Modifier and Type | Field and Description |
|---|---|
protected java.lang.Class<?> |
currentType |
protected GenericsInfo |
genericsInfo |
protected java.util.Map<java.lang.String,java.lang.reflect.Type> |
typeGenerics |
| Constructor and Description |
|---|
AbstractGenericsContext(GenericsInfo genericsInfo,
java.lang.Class<?> type) |
| Modifier and Type | Method and Description |
|---|---|
abstract GenericsContext |
chooseContext(java.lang.reflect.Type type)
Look for generic variables presence inside type and, if found, try to switch to correct context.
|
abstract ConstructorGenericsContext |
constructor(java.lang.reflect.Constructor constructor)
Navigates current context to specific constructor (type context is switched to constructor declaring class).
|
protected abstract java.util.Map<java.lang.String,java.lang.reflect.Type> |
contextGenerics() |
java.lang.Class<?> |
currentClass() |
GenericsContext |
fieldType(java.lang.reflect.Field field)
Create generics context for field type (with correctly resolved root generics)."
|
GenericsContext |
fieldTypeAs(java.lang.reflect.Field field,
java.lang.Class<?> asType)
Create generics context for type extending field type.
|
java.lang.Class<?> |
generic(int position)
class A extends B<Object, C<Long>>. |
java.lang.Class<?> |
generic(java.lang.String genericName)
class B<T, K>. |
java.lang.String |
genericAsString(int position)
class A extends B<Object, C<Long>>. |
java.lang.String |
genericAsString(java.lang.String genericName)
class B<T, K>. |
java.util.List<java.lang.Class<?>> |
generics()
class A extends B<Object, C<Long>>. |
java.util.List<java.lang.String> |
genericsAsString()
class A extends B<Object, C<Long>>. |
java.util.Map<java.lang.String,java.lang.reflect.Type> |
genericsMap()
class A extends B<Object, C<Long>> and class B<T, K>. |
java.lang.reflect.Type |
genericType(int position)
class A extends B<Object, C<Long>>. |
java.lang.reflect.Type |
genericType(java.lang.String genericName)
class B<T, K>. |
java.util.List<java.lang.reflect.Type> |
genericTypes()
class A extends B<Object, C<Long>>. |
GenericsInfo |
getGenericsInfo() |
abstract GenericDeclarationScope |
getGenericsScope()
For example,
CLASS scope could resolve only class level generics, whereas
METHOD could see method context generics. |
abstract java.lang.reflect.GenericDeclaration |
getGenericsSource()
Declaration source could be: class, method or constructor.
|
abstract GenericsContext |
inlyingType(java.lang.reflect.Type type)
Build generics context for type in context of current class.
|
abstract GenericsContext |
inlyingTypeAs(java.lang.reflect.Type type,
java.lang.Class<?> asType)
Build generics context for type extending some generic type in context of current class.
|
abstract MethodGenericsContext |
method(java.lang.reflect.Method method)
Navigates current context to specific method (type context is switched to method declaring class).
|
java.lang.Class<?> |
resolveClass(java.lang.reflect.Type type)
Useful for introspection to know exact class of type.
|
java.lang.Class<?> |
resolveFieldClass(java.lang.reflect.Field field)
Shortcut for
resolveClass(Type) for fields (same as resolveClass(field.getGenericType()). |
java.lang.Class<?> |
resolveFieldGeneric(java.lang.reflect.Field field)
Shortcut for
resolveGenericOf(Type) for fields
(same as resolveGenericOf(field.getGenericType())). |
java.util.List<java.lang.Class<?>> |
resolveFieldGenerics(java.lang.reflect.Field field)
Shortcut for
resolveGenericsOf(Type) for fields (same as
resolveGenericsOf(field.getGenericType()). |
java.lang.reflect.Type |
resolveFieldType(java.lang.reflect.Field field)
List<T> field could be resolved as resolveFiledType(field) == List<String> as ParameterizedType
(if T == String). |
java.lang.Class<?> |
resolveGenericOf(java.lang.reflect.Type type)
Shortcut for
resolveGenericsOf(Type) useful for single generic types or
when just first generic required. |
java.util.List<java.lang.Class<?>> |
resolveGenericsOf(java.lang.reflect.Type type)
Useful for introspection, to know exact generic value.
|
java.lang.reflect.Type |
resolveType(java.lang.reflect.Type type)
Replace all named variables in type with actual generics.
|
java.util.List<java.lang.reflect.Type> |
resolveTypeGenerics(java.lang.reflect.Type type)
Returns generics of type with all named variables replaced in types with actual generics.
|
protected abstract GenericsContext |
switchContext(java.lang.Class target,
java.lang.String msgPrefix)
Used to switch to appropriate context or fail if type is not found in hierarchy.
|
java.lang.String |
toStringCurrentClass()
For example,
class Root extends Base<String> (and we resolve generics from Root):
context.toStringCurrentClass() == "Root" and
context.type(Base.class).toStringCurrentClass() == "Base<String>". |
java.lang.String |
toStringCurrentClassDeclaration()
For example,
Base<T>. |
java.lang.String |
toStringType(java.lang.reflect.Type type)
Useful for reporting or maybe logging.
|
abstract GenericsContext |
type(java.lang.Class<?> type)
Navigates current context to specific type in class hierarchy.
|
java.util.Map<java.lang.String,java.lang.reflect.Type> |
visibleGenericsMap()
All reachable generics.
|
protected final GenericsInfo genericsInfo
protected final java.lang.Class<?> currentType
protected final java.util.Map<java.lang.String,java.lang.reflect.Type> typeGenerics
public AbstractGenericsContext(GenericsInfo genericsInfo, java.lang.Class<?> type)
public java.lang.Class<?> currentClass()
public java.util.List<java.lang.reflect.Type> genericTypes()
class A extends B<Object, C<Long>>.
type(B.class).genericTypes() == [Class<Object>, ParametrizedType]
Note: always returns all declared class generics, even inside method or constructor context, where class generics could be hidden by context generics with the same name.
public java.util.List<java.lang.Class<?>> generics()
class A extends B<Object, C<Long>>.
type(B.class).generics() == [Class<Object>, Class<C>]
Note that this way you loose second level generics info (Long from C class)
Note: always returns all declared class generics, even inside method or constructor context, where class generics could be hidden by context generics with the same name.
public java.util.List<java.lang.String> genericsAsString()
class A extends B<Object, C<Long>>.
type(B.class).genericsAsString() == ["Object", "C<Long>"]
Note, that returned generics are completely resolved, e.g.
A extends B<Object> , where B<T> extends C<T, List<T>>,
and when we call type(C.class).genericsAsString() == ["Object", "List<Object>]
Note: always returns all declared class generics, even inside method or constructor context, where class generics could be hidden by context generics with the same name.
public java.lang.reflect.Type genericType(int position)
class A extends B<Object, C<Long>>.
type(B.class).genericType(1) == ParametrizedType position - generic position (from 0)java.lang.IndexOutOfBoundsException - for wrong indexfor detailspublic java.lang.reflect.Type genericType(java.lang.String genericName)
class B<T, K>.
class A extends B<Object, C<Long>>
type(B.class).genericType("K") == ParametrizedType
Note: will work for any visible generic (from current context) including outer class, method and constructor generics.
genericName - generic position (from 0)UnknownGenericException - for wrong generic namefor detailspublic java.lang.Class<?> generic(int position)
class A extends B<Object, C<Long>>.
type(B.class).generic(1) == C.class position - generic position (from 0)java.lang.IndexOutOfBoundsException - for wrong indexresolveClass(java.lang.reflect.Type)public java.lang.Class<?> generic(java.lang.String genericName)
class B<T, K>.
class A extends B<Object, C<Long>>
type(B.class).generic("K") == C.class
Note: will work for any visible generic (from current context) including outer class, method and constructor generics.
genericName - generic nameUnknownGenericException - for wrong generic nameresolveClass(java.lang.reflect.Type)public java.lang.String genericAsString(int position)
class A extends B<Object, C<Long>>.
type(B.class).genericAsString(1) == "C<Long>" position - generic position (from 0)java.lang.IndexOutOfBoundsException - for wrong indextoStringType(java.lang.reflect.Type)public java.lang.String genericAsString(java.lang.String genericName)
class B<T, K>.
class A extends B<Object, C<Long>>
type(B.class).genericAsString("K") == "C<Long>"
Note: will work for any visible generic (from current context) including outer class and method generics
genericName - generic namejava.lang.IllegalArgumentException - for wrong generic nametoStringType(java.lang.reflect.Type)public java.util.Map<java.lang.String,java.lang.reflect.Type> genericsMap()
class A extends B<Object, C<Long>> and class B<T, K>.
type(B.class).genericsMap() == ["T": Object.class, "K": ParametrizedType]
Note: always returns all declared class generics, even inside method or constructor context, where class generics could be hidden by context generics with the same name.
for all visible generics in current contextpublic java.util.Map<java.lang.String,java.lang.reflect.Type> visibleGenericsMap()
Self<T, K>)Outer<T>.Inner<K>)<T> T get())for type only generics,
MethodGenericsContext.methodGenericsMap(),
GenericsContext.ownerGenericsMap()public GenericsInfo getGenericsInfo()
public java.lang.Class<?> resolveClass(java.lang.reflect.Type type)
class A extends B<Long>;
class B<T> {
T doSmth();
}
Resolving class of return type:
type(B.class).resolveClass(B.class.getMethod("doSmth").getGenericReturnType()) == Long.class
Check if type containing generics, belonging to different context in current hierarchy and automatically change context to properly resolve generics. Fails when it is impossible to correctly resolve generics (preventing incorrect usage).
Note: may return primitive because it might be important to differentiate actual value.
Use TypeUtils.wrapPrimitive(Class) to box possible primitive,
if required.
type - type to resolve classWrongGenericsContextException - if type contains generics not visible from current classpublic java.lang.Class<?> resolveFieldClass(java.lang.reflect.Field field)
resolveClass(Type) for fields (same as resolveClass(field.getGenericType()).
Use for more informative error message on incorrect usage.
Automatically choose correct context or fail if field does not belong to current hierarchy.
Note: may return primitive because it might be important to differentiate actual value.
Use TypeUtils.wrapPrimitive(Class) to box possible primitive,
if required.
field - field to resolve typejava.lang.IllegalArgumentException - if field not belongs to any class in hierarchypublic java.util.List<java.lang.Class<?>> resolveGenericsOf(java.lang.reflect.Type type)
class A extends B<Long>;
class B<T> {
List<T> doSmth();
}
Resolving parameters in context of root class:
type(B.class).resolveGenericsOf(B.class.getMethod("doSmth").getGenericReturnType()) == [Long.class]
When called on class, return upper bound from generic declaration.
Check if type containing generics, belonging to different context in current hierarchy and automatically change context to properly resolve generics. Fails when it is impossible to correctly resolve generics (preventing incorrect usage).
type - type to resolve genericsWrongGenericsContextException - if type contains generics not visible from current classif complete types are requiredpublic java.util.List<java.lang.Class<?>> resolveFieldGenerics(java.lang.reflect.Field field)
resolveGenericsOf(Type) for fields (same as
resolveGenericsOf(field.getGenericType()).
Use for more informative error message on incorrect usage.
Automatically choose correct context or fail if field does not belong to current hierarchy.
field - field to resolve generics forjava.lang.IllegalArgumentException - if field not belongs to any class in hierarchyfor complete example of possible issuespublic java.lang.Class<?> resolveGenericOf(java.lang.reflect.Type type)
resolveGenericsOf(Type) useful for single generic types or
when just first generic required.
Check if type containing generics, belonging to different context in current hierarchy and automatically change context to properly resolve generics. Fails when it is impossible to correctly resolve generics (preventing incorrect usage).
type - type to resolve genericpublic java.lang.Class<?> resolveFieldGeneric(java.lang.reflect.Field field)
resolveGenericOf(Type) for fields
(same as resolveGenericOf(field.getGenericType())).
Use for more informative error message on incorrect usage.
Automatically choose correct context or fail if field does not belong to current hierarchy.
field - field to resolve generic forjava.lang.IllegalArgumentException - if field not belongs to any class in hierarchyfor complete example of possible issuespublic java.lang.reflect.Type resolveFieldType(java.lang.reflect.Field field)
List<T> field could be resolved as resolveFiledType(field) == List<String> as ParameterizedType
(if T == String).
Automatically choose correct context or fail if field does not belong to current hierarchy.
field - field to resolve generics forjava.lang.IllegalArgumentException - if field not belongs to any class in hierarchypublic java.lang.reflect.Type resolveType(java.lang.reflect.Type type)
ParameterizedType List<T>
would become ParameterizedType List<String> (assuming generic T is defined as String).
More complex cases could arrive like T[] or ? extends T, but everything will be correctly
replaced by actual (known) types, so you could be sure that returned type contains all known type information
and does not contain variables.
Useful when complete type information is required elsewhere (for example, to create typed DI binding).
Check if type containing generics, belonging to different context in current hierarchy and automatically change context to properly resolve generics. Fails when it is impossible to correctly resolve generics (preventing incorrect usage).
type - type to resolve named generics inWrongGenericsContextException - if type contains generics not visible from current classpublic java.util.List<java.lang.reflect.Type> resolveTypeGenerics(java.lang.reflect.Type type)
ParameterizedType Map<String, List<T>> would become
[Class String, ParameterizedType List<String>] (assumed generic T is defined as String).
Note: if type is Class then return raw generics definition (for consistency).
Useful when complete generic types are required.
Check if type containing generics, belonging to different context in current hierarchy and automatically change context to properly resolve generics. Fails when it is impossible to correctly resolve generics (preventing incorrect usage).
type - type to return resolved generics ofWrongGenericsContextException - if type contains generics not visible from current classif just classes requiredpublic java.lang.String toStringType(java.lang.reflect.Type type)
class A extends B<Long>;
class B<T> {
List<T> doSmth();
}
Resolving parameters in type of root class:
type(B.class).toStringType(B.class.getMethod("doSmth").getGenericReturnType()) == "List<Long>"
Check if type containing generics, belonging to different context in current hierarchy and automatically change context to properly resolve generics. Fails when it is impossible to correctly resolve generics (preventing incorrect usage).
type - to to get string ofWrongGenericsContextException - if type contains generics not visible from current classpublic abstract GenericsContext type(java.lang.Class<?> type)
type - class to navigate tojava.lang.IllegalArgumentException - if requested class not present in root class hierarchypublic abstract MethodGenericsContext method(java.lang.reflect.Method method)
<T> void myMethod(T arg);.
Use context to work with method parameters, return type or resolving types inside method.
method - method in current class hierarchy to navigate to (may be method from subclass, relative to
currently selected, in this case context type will be automatically switched)java.lang.IllegalArgumentException - if requested method's declaration class is not present in current class
hierarchypublic abstract ConstructorGenericsContext constructor(java.lang.reflect.Constructor constructor)
<T> MyType(T arg).
Use context to work with constructor arguments.
constructor - constructor in current class hierarchy to navigate to (may be constructor from subclass,
relative to currently selected, in this case context type is automatically switched)java.lang.IllegalArgumentException - if requested constructor's declaration class is not present in current class
hierarchypublic GenericsContext fieldType(java.lang.reflect.Field field)
class A<T> {
private B<T> field;
}
class C extends A<String> {}
Build generics context for field type (to continue analyzing field class fields):
type(A.class).fieldType(A.class.getField("field")) == generics context of B<String>
Note that, in contrast to direct resolution GenericsResolver.resolve(B.class), actual root generic
would be counted for hierarchy resolution.
field - field in current class hierarchy to resolve type from (may be field from superclass, relative to
currently selected, in this case context type will be automatically switched)java.lang.IllegalArgumentException - if field not belongs to any class in hierarchyinlyingType(Type)public GenericsContext fieldTypeAs(java.lang.reflect.Field field, java.lang.Class<?> asType)
Other than that, method is almost the same as fieldType(Field).
field - field in current class hierarchy to resolve type from (may be field from superclass, relative to
currently selected, in this case context type will be automatically switched)asType - required actual root type (extending field type)java.lang.IllegalArgumentException - if field not belongs to any class in hierarchyinlyingTypeAs(Type, Class)public abstract GenericsContext inlyingType(java.lang.reflect.Type type)
class A<T> {
private C<T> field;
}
class C extends A<String> {}
To continue analysis of field type: type(A.class).inlyingType(A.class.getField("field")
.getGenericType()) == generics context of C<String>
Use shortcut methods to simplify navigation: fieldType(Field),
MethodGenericsContext.returnType(), MethodGenericsContext.parameterType(int) and
ConstructorGenericsContext.parameterType(int).
Check if type containing generics, belonging to different context in current hierarchy and automatically change context to properly resolve generics. Fails when it is impossible to correctly resolve generics (preventing incorrect usage).
If provided type did not contains generic then cached type resolution will be used (the same as
GenericsResolver.resolve(Target.class) and if generics present then type will be built on each call.
Returned context holds reference to original (root) context: GenericsContext.rootContext().
Ignored types, used for context creation, are counted (will also be ignored for inlying context building).
type - type to resolve hierarchy from (it must be generified type, resolved in current class)WrongGenericsContextException - if type contains generics not visible from current classpublic abstract GenericsContext inlyingTypeAs(java.lang.reflect.Type type, java.lang.Class<?> asType)
Example case: field declaration is SomeInterface<T> field and we need to build inlying context
for actual field value class SomeImpl<K> implements SomeInterface<K>. Type of root generic K will be
tracked from known generic T (on interface), but even if it's not possible to track root generics, hierarchy
starting from known type (interface in this case) will use correct generic value. This way, all known
generics information is used.
Other than different target type, method is the same as inlyingType(Type). By analogy, shortcuts
are provided for simpler navigation: fieldTypeAs(Field, Class),
MethodGenericsContext.returnTypeAs(Class), MethodGenericsContext.parameterTypeAs(int, Class)
and ConstructorGenericsContext.parameterTypeAs(int, Class).
type - type to resolve actual generics from (it must be generified type, resolved in current class)asType - required target type to build generics context for (must include declared type as base class)WrongGenericsContextException - if type contains generics not visible from current classinlyingType(Type)public abstract GenericsContext chooseContext(java.lang.reflect.Type type)
Note that WrongGenericsContextException used instead of IllegalArgumentException, as in
other cases, because it is more specific error: type may come from anywhere and it may be not so easy to
track it's correct usage.
type - type, possibly containing generic variablesWrongGenericsContextException - when it is impossible to resolve type in correct contextpublic java.lang.String toStringCurrentClass()
class Root extends Base<String> (and we resolve generics from Root):
context.toStringCurrentClass() == "Root" and
context.type(Base.class).toStringCurrentClass() == "Base<String>".public java.lang.String toStringCurrentClassDeclaration()
Base<T>.
context.type(Base.class).toStringCurrentClassDeclaration() == "Base<T>".public abstract GenericDeclarationScope getGenericsScope()
CLASS scope could resolve only class level generics, whereas
METHOD could see method context generics. May be used for current context differentiation
(instead of instanceof).getGenericsSource()public abstract java.lang.reflect.GenericDeclaration getGenericsSource()
getGenericsScope()protected abstract java.util.Map<java.lang.String,java.lang.reflect.Type> contextGenerics()
protected abstract GenericsContext switchContext(java.lang.Class target, java.lang.String msgPrefix)
Note that this method may seem useless as correct context is always selected based on type generics, but method is required to show more specific error (better indicating context).
target - target typemsgPrefix - error message prefix, identifying placejava.lang.IllegalArgumentException - when context can't be switchedchooseContext(Type)