2

So, I have created several custom annotations:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Foo {

}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Bar {

}

Those annotations are used in my functions:

public class Worker {

   @Foo
   public void doTaskOne() {...}

   @Bar
   public void doTaskX() {...}

   ...
}

I want to use java reflection to check if certain annotation is declared in one method.

for (Method m : methods) {
      if (m.isAnnotationPresent(Foo.class)) {
        ...
      } else if (m.isAnnotationPresent(Bar.class)) {
        ...
      }
}

The problem is that since in Java, custom annotation @interface is not able to be extended. I mean this is illegal:

public @interface Bar extends MyBaseAnnotation{
}

That's I am not able to have a base @interface for all my custom annotation class Foo and Bar. So, if I have a new custom annotation created, I need to add more else if condition in above method checking code, which sucks! Is there anyway to get rid of this problem? What I want to achieve is to generalize my method checking code to :

for (Method m : methods) {
     if (m.isAnnotationPresent(MyBaseAnnotation.class)) {
         ...
     }
}

How to achieve it?

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Leem.fin
  • 40,781
  • 83
  • 202
  • 354

2 Answers2

0

You can annotate your custom annotations with a base custom annotation, like composed annotations do.

Instead of:

public @interface Bar extends MyBaseAnnotation{
}

use:

@MyBaseAnnotation
public @interface Bar {
}
Gustavo Passini
  • 2,348
  • 19
  • 25
  • Annotation of annotations? How am I supposed to use this tactic in my method checking method? – Leem.fin Sep 20 '19 at 14:37
  • With a simple helper method, like the one @AndrewTobilko showed in his answer. If you are using Spring, you could take a look at [AnnotationUtils](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html) – Gustavo Passini Sep 20 '19 at 15:36
0

Assuming that

@Parent
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Foo {}

@Parent
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Bar {}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface Parent {}

and there is a method

public static boolean isAnnotationPresent(Method method, Class<? extends Annotation> parentAnnotation) throws NoSuchMethodException {
    for (Annotation methodAnnotation : method.getDeclaredAnnotations()) {
        if (methodAnnotation.annotationType().isAnnotationPresent(parentAnnotation)) {
            return true;
        }
    }
    return false;
}

you can do

isAnnotationPresent(m, Parent.class)

You got it right: there is no inheritance between annotation types in Java. You could make your own rules, though. By saying "if annotation B has annotation A over it, then B extends A", you define the rule that you will follow while using reflection.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • Can I have method in parent annotation so that the method checking function can call it for all my annotations? In other words, all "inherited" annotations inherit this method? `public @interface Parent { String value() default ""; }` – Leem.fin Sep 20 '19 at 14:41
  • No, you can try to use/copy similar mechanism as Spring uses, but it's pretty complicated one, and requires creating whole own annotation API and implementing own annotations at runtime using own proxy classes. As then you could read data from parent annotation and copy it to child ones when your api method is used. But I would not suggest such hacky solution in any situation. Maybe try to simplify your annotation usage instead. – GotoFinal Sep 23 '19 at 09:20
  • But if you will want to do it anyways @Leem.fin I can try to help a bit more – GotoFinal Sep 23 '19 at 09:21