lquerel
lquerel

Reputation: 183

How to capture annotations on generic super class type arguments?

With java 8 it's possible to create an annotation with the target ElementType.TYPE_USE.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE})
public @interface MyAnnotation {
}

This annotation can be applied on types passed to a generic super class, for example:

public class ClassA extends BaseClass<@MyAnnotation ClassB,@MyAnnotation ClassC>{
...
}

With the following code, I can easily retrieved dynamically from an instance of ClassA the list of type parameters of the super class BaseClass.

ClassA instanceOfA = new ClassA();
...
Class classOfA = instanceOfA.getClass();
ParameterizedType type =  (ParameterizedType)classOfA.getGenericSuperclass();
Type[] types = type.getActualTypeArguments();

// types[0] --> ClassB
// types[1] --> ClassC

From there, I tried to find a way to retrieve the annotation for each type argument but without success.

Is there a way to retrieve these annotations dynamically (runtime)? Thanks

Edit: Additional precision, I would like to support the following use case:

public class ClassA extends BaseClass<@Annotation1 ClassB,@Annotation2 ClassC>{
...
}

public class ClassD extends BaseClass<@Annotation3 ClassB,@Annotation4 ClassC>{
...
}

In this example, ClassB is annotated differently in the context of ClassA or ClassD (same thing for ClassC).

Upvotes: 3

Views: 1593

Answers (2)

bprasanna
bprasanna

Reputation: 2453

For annotations at class level we can use getAnnotations() method for each class object. In your code we need to type cast the Type to Class and get annotations for it.

For example:

Class classOfA = instanceOfA.getClass();
ParameterizedType type =  (ParameterizedType)classOfA.getGenericSuperclass();
Type[] types = type.getActualTypeArguments();

for(Type t: types){
    System.out.println(t.getTypeName());

    Annotation[] ans = ((Class) t).getAnnotations();
    for(Annotation an: ans){
        System.out.println(an.annotationType());
    }
}

Following is a complete example with two different annotations to highlight the difference:

import java.lang.annotation.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class AnnotationChecker {

    public static void main(String[] args) {
        ClassA instanceOfA = new ClassA();

        Class classOfA = instanceOfA.getClass();
        ParameterizedType type =  (ParameterizedType)classOfA.getGenericSuperclass();
        Type[] types = type.getActualTypeArguments();

        for(Type t: types){
            System.out.println(t.getTypeName());

            Annotation[] ans = ((Class) t).getAnnotations();
            for(Annotation an: ans){
                System.out.println(an.annotationType());
            }
        }

    }

}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotation1 {

}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotation2 {

}


class ClassA extends BaseClass<ClassB,ClassC>{

}

class BaseClass<ClassB, ClassC> {

}

@MyAnnotation1
class ClassB {

}

@MyAnnotation2
class ClassC {

}

Upvotes: 0

wero
wero

Reputation: 32980

Tricky:

 import java.lang.reflect.*;

 AnnotatedType baseClassAt = classOfA.getAnnotatedSuperclass();
 assert (at instanceof AnnotatedParameterizedType);

 AnnotatedType[] aTypes = ((AnnotatedParameterizedType)baseClassAt)
     .getAnnotatedActualTypeArguments();
 assert aTypes.length == 2;

 MyAnnotation myAnno0 = aTypes[0].getAnnotation(MyAnnotation.class);
 MyAnnotation myAnno1 = aTypes[1].getAnnotation(MyAnnotation.class);

Upvotes: 4

Related Questions