All type annotations can be retrieved through the AnnotatedType hierarchy, except for the TypeVariable, whose annotations can be retrieve through AnnotatedTypeVariable.getType() which will be an instance of TypeVariable which extends AnnotatedElement now and happens to be identical with the object returned by Method.getGenericReturnType().
So you can retrieve all information, e.g.
AnnotatedType art = myMethod.getAnnotatedReturnType();
System.out.print(
Arrays.toString(art.getAnnotations())+" "+art.getType().getTypeName()+" -> ");
final boolean typeVariable = art instanceof AnnotatedTypeVariable;
if (typeVariable) System.out.print('<');
System.out.print(Arrays.toString(((AnnotatedElement)art.getType()).getAnnotations()) + " ");
System.out.print(art.getType().getTypeName());
if (typeVariable) {
AnnotatedTypeVariable atv = (AnnotatedTypeVariable)art;
AnnotatedType[] annotatedBounds = atv.getAnnotatedBounds();
if (annotatedBounds.length > 0) {
System.out.print(" extends ");
for (AnnotatedType aBound: annotatedBounds) {
System.out.print(Arrays.toString(aBound.getAnnotations()) + " ");
System.out.print(aBound.getType().getTypeName() + ", ");
}
}
System.out.println(">");
}
will print
[@A3()] S -> <[@A1()] S extends [@A2()] T, >
When your invocation of ((AnnotatedTypeVariable)myMethod.getAnnotatedReturnType()) .getAnnotatedBounds()[0].getAnnotations() does not provide @A2, you should recheck that A2 truly has @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE).
Of course, that’s the “simplified” version handling only your specific method.
To handle all possible cases, you will need much more instanceofs, dealing with these disjunct type hierarchies of Type and AnnotatedType, especially when processing annotated parameterized types and annotated generic array types.
As said, TypeVariable is different, as it extends AnnotatedElement and also has the getAnnotatedBounds() method. So in this specific case, an alternative way to process the method is
List<TypeVariable<?>> typeParameters = Arrays.asList(myMethod.getTypeParameters());
for (TypeVariable<?> tv: typeParameters) {
System.out.print("< "+Arrays.toString(tv.getAnnotations())+" "+tv.getName());
AnnotatedType[] annotatedBounds = tv.getAnnotatedBounds();
if (annotatedBounds.length > 0) {
System.out.print(" extends ");
for (AnnotatedType aBound: annotatedBounds) {
System.out.print(Arrays.toString(aBound.getAnnotations()) + " ");
System.out.print(aBound.getType().getTypeName() + ", ");
}
}
System.out.print("> ");
}
AnnotatedType art = myMethod.getAnnotatedReturnType();
System.out.print(Arrays.toString(art.getAnnotations()) + " ");
int ix = typeParameters.indexOf(art.getType());
if (ix >= 0) System.out.print("[ref to type parameter #" + ix + "] ");
System.out.println(art.getType().getTypeName());