- Notifications
You must be signed in to change notification settings - Fork18
Advanced generic type reflection library with support for working with AnnotatedTypes (for Java 8+)
License
leangen/geantyref
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A fork of the excellentGenTyRef library, adding support for working withAnnotatedTypes introduced in Java 8 plus many nifty features.
Table of Contents
- GeantyRef
- Goal
- Overview
- Usage
- Examples
- Getting the exact return type of a method
- Getting the exact type of a field
- Getting the exact types of method parameters
- Getting the exact super type
- Getting the exact sub type
- Getting annotated return/parameter/field/sub/super types
- Creating type literals using TypeToken
- Creating annotated type literals using TypeToken
- Creating types dynamically using TypeFactory
- Creating annotated types dynamically using TypeFactory
- Turning any Type into an AnnotatedType
- More
- Wiki
- License
This library aims to provide a simple way to analyse generic type information and dynamically create(Annotated)Type
instances, all at runtime.
All functionality of the library is exposed via a handful of classes:
GenericTypeReflector
: contains static methods used for generic type analysisTypeFactory
: contains static methods used forType/AnnotatedType
instance creationTypeToken
: Used to createType/AnnotatedType
literals (usingTHC pattern)
<dependency> <groupId>io.leangen.geantyref</groupId> <artifactId>geantyref</artifactId> <version>2.0.0</version></dependency>
You can find instructions atmaven.org
The simplest example would be having a class similar to this:
classStringListextendsArrayList<String> { ...}
Getting the exact return type ofStringList
'sget
method is rather difficult:
Methodget =StringList.class.getMethod("get",int.class);get.getGenericReturnType()//yields T, which is not very useful information
On the other hand, runningGenericTypeReflector.getExactReturnType(get, StringClass.class)
would yieldString
which is what we were looking for.
Presume we have two simple classes:
classContainer<T> {publicTitem;}classNumberContainerextendsContainer<Number> {}
We again face issues when trying to discover the exact type of theitem
field:
Fielditem =NumberContainer.class.getField("item");item.getGenericType();//yields T again
Instead,GenericTypeReflector.getExactFieldType(item, NumberContainer.class)
returnsNumber
as desired.
GenericTypeReflector.getExactParameterTypes(methodOrConstructor, aType)
If we had the classes defined as follows:
classContainer<T> {publicTitem;}classNumberContainer<TextendsNumber>extendsContainer<T> {}classLongContainerextendsNumberContainer<Long> {}
If we'd callLongContainer.class.getGenericSuperclass()
it would correctly returnNumberContainer<Long>
but getting from there toContainer<Long>
is much more difficult, as there's no direct way.
GeantyRef allows us to simply callGenericTypeReflector.getExactSuperType(LongContainer.class, Container.class)
to getContainer<Long>
Even more interestingly, it is sometimes possible to get the exact sub type of a type.For example, if we hadList<String>
and we wantedArrayList<String>
if would be possible,as theArrayList
's sole type parameter is coming fromList
, i.e.ArrayList
does not defineany type parameters itself,List<String>
already contains all the needed information.This is rather difficult to calculate using standard reflection, but if we already had a reference toList<String>
calledlistOfString
, it is enough to call:
GenericTypeReflector.getExactSubType(listOfString, ArrayList.class)
to getArrayList<String>
Still, how to get tolistOfString
? Probably by calling one of the methods described above.But, it's also possible to create a type literal directly viaTypeToken
, or construct the desiredType
(List<String>
) dynamically usingTypeFactory
.
It is worth noting that all the basic methods on theGenericTypeReflector
listed above haveoverloads that work withAnnotatedType
s.
classPerson {publicList<@NonNullString>nicknames;}AnnotatedTypelistOfNonNullStrings =Person.class.getField("nicknames").getAnnotatedType();Methodget =List.class.getMethod("get",int.class);//returns an AnnotatedType representing: @NonNull StringAnnotatedTypenonNullString =GenericTypeReflector.getExactReturnType(get,listOfNonNullStrings);
Similarly,getExactFieldType
,getExactParameterTypes
,getExactSuperType
,getExactSubType
work withAnnotatedType
s.
This approach, known asTypesafe Heterogenous Container (THC) ortype token, is widely usedin libraries like Jackson or Gson that need to work with generic types. There are various sourcesdescribing the intricacies of this approach,Neal Gafter's blog being a classic one.
To obtain aType
instance representing a know generic type, such asList<String>
it is enough todo the following:
Type listOfString = new TypeToken<List<String>>(){}.getType();
What we're doing here is creating an anonymous subclass of a parameterized type (TypeToken
) andgetting it's generic super class viagetGenericSuperclass
.
If instead we wanted an instance of an annotated type, such asList<@NonNull String>
, the sameprinciple would apply:
AnnotatedType listOfNonNullString = new TypeToken<List<@NonNull String>>(){}.getAnnotatedType();
TypeToken
is only useful if all the generic type information is known ahead of time. It will notallow us to create aType
orAnnotatedType
dynamically. For such a task,TypeFactory
providesadequate methods.
Class<List>listType =List.class;Class<String>typeParameter =String.class;//returns a Type representing List<String>TypelistOfStrings =TypeFactory.parameterizedClass(listType,typeParameter);Class<Map>mapType =Map.class;Class<String>keyTypeParameter =String.class;Class<Number>valueTypeParameter =Number.class;//returns a Type representing Map<String, Number>TypemapOfStringNumber =TypeFactory.parameterizedClass(mapType,keyTypeParameter,valueTypeParameter);
TypeFactory
can also produceAnnotatedType
instances, but this means we need to somehow obtaininstances of the annotations themselves (instances ofAnnotation
).An obvious way of getting them would be from an existingAnnotatedElement
(annotatedElement.getAnnotations()
).Class
,Parameter
,Method
,Constructor
,Field
all implementAnnotatedElement
.
But,TypeFactory
also allows you to instantiate anAnnotation
dynamically:
Map<String,Object>annotationParameters =newHashMap<>();annotationParameters.put("name","someName");MyAnnotationmyAnnotation =TypeFactory.annotation(MyAnnotation.class,annotationParameters);
This produces anAnnotation
instance as if@MyAnnotation(name = "someName")
was found in the sources.
Armed with this knowledge, it's easy to produce anAnnotatedType
:
Class<List>listType =List.class;Class<String>typeParameter =String.class;Annotation[]annotations = {myAnnotation };//returns an AnnotatedType representing: @MyAnnotation(name = "someName") List<String>AnnotatedTypeannotatedListOfString =TypeFactory.parameterizedClass(listType,annotations,typeParameter);
GenericTypeReflector
also allows you to wrap anyType
into anAnnotatedType
by collecting itsdirect annotations. For example:
@SuppressWarnings("unchecked")classSomething {}//returns an AnnotatedType representing: @SuppressWarnings("unchecked") SomethingAnnotatedTypesomething =GenericTypeReflector.annotate(Something.class);
This method will correctly turn aParameterizedType
into anAnnotatedParameterizedType
,WildcardType
into anAnnotatedWildcardType
etc.
To turn aParameterizedType
into anAnnotatedParameterizedType
with customized annotations:
TypelistOfStrings =TypeFactory.parameterizedClass(List.class,String.class);Annotation[]typeAnnotations = {myAnnotation };Annotation[]argumentAnnotations = {anotherAnnotation };//Get an AnnotatedParameterizedType representing: @MyAnnotation List<@AnotherAnnotation String>AnnotatedParameterizedTypeannotatedListOfAnnotatedStrings =parameterizedAnnotatedType(listOfStrings,typeAnnotations,argumentAnnotations);
There are more features provided byGenericTypeReflector
that were not described in depth here,like the possibility to replace annotations on anAnnotatedType
viareplaceAnnotations
,or update them viaupdateAnnotations
, calculate hash codes and check equality ofAnnoatedType
s(asequals
andhasCode
are not overridden in Java'sAnnotatedType
implementations) etc, sofeel free to explore a bit on your own.
More info can be found at the projectWiki.
About
Advanced generic type reflection library with support for working with AnnotatedTypes (for Java 8+)
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Languages
- Java100.0%