6

I m trying to get the annotation details from super type reference variable using reflection, to make the method accept all sub types. But isAnnotationPresent() returning false. Same with other annotation related methods. If used on the exact type, output is as expected.

I know that annotation info will be available on the Object even I m referring through super type.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Table {
    String name();
}
@Table(name = "some_table")
public class SomeEntity {

    public static void main(String[] args) {
        System.out.println(SomeEntity.class.isAnnotationPresent(Table.class)); // true
        System.out.println(new SomeEntity().getClass().isAnnotationPresent(Table.class)); // true

        Class<?> o1 = SomeEntity.class;
        System.out.println(o1.getClass().isAnnotationPresent(Table.class)); // false

        Class<SomeEntity> o2 = SomeEntity.class;
        System.out.println(o2.getClass().isAnnotationPresent(Table.class)); // false

        Object o3 = SomeEntity.class;
        System.out.println(o3.getClass().isAnnotationPresent(Table.class)); // false
    }
}

How to get the annotation info?

manikanta
  • 7,066
  • 5
  • 52
  • 61

4 Answers4

19

You're calling getClass() on a Class<?>, which will give Class<Class>. Now Class itself isn't annotated, which is why you're getting false. I think you want:

// Note no call to o1.getClass()
Class<?> o1 = SomeEntity.class;
System.out.println(o1.isAnnotationPresent(Table.class));
Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • 2
    Oh my! How could I miss that :( I m changing some code repeatedly and missed to remove the `getClass()` after changing the method parameter from `Object` to `Class`. I knew my question is so dumb as I've done similar thing thousand times. Thanks for spotting my ignorance. – manikanta Sep 29 '11 at 14:56
  • 1
    @mrCoder typical "abuse of copy-paste" issue... Everyone falls into this one :) – Romain Sep 29 '11 at 14:59
  • @Romain Yeah, quite some time we can't help with that. ha ha – manikanta Sep 29 '11 at 15:00
  • But to get the annotation info when referring using `Object`? Is it possible? the last case in my OP. Thanks – manikanta Sep 29 '11 at 15:02
  • 1
    @mrCoder It'll work if you set `o3` to an instance of `SomeEntity`, and then call `getClass().isAnnotationPresent(...)` on it. But as you write it, it simply cannot work (at least not in a way that static typing easily allows). – Romain Sep 29 '11 at 15:05
  • @mrCoder: You'd have to cast to `Class>`: `Class> clazz = (Class>) o3;` - but if you've got a class reference, why have you only got it as `Object` to start with? – Jon Skeet Sep 29 '11 at 15:05
  • Previous code accepts `Object` and at that time `getClass()` is used. Later I've changed to `Class`, but missed to remove the `getClass()` – manikanta Sep 29 '11 at 15:10
  • To show you the previous code, `void some(Object o) { System.out.println(o.getClass().isAnnotationPresent(Table.class)); }` and calling the method like `some(SomeEntity.class);`. It was written like that to support all types (objects, classes, ...) – manikanta Sep 29 '11 at 15:14
  • @mrCoder: Can you change it to `some(AnnotatedElement o)` instead? Then just use `System.out.println(o.isAnnotationPresent(Table.class));` – Jon Skeet Sep 29 '11 at 15:17
  • I'll try that, thanks. But my initial guess is that even if that worked, it'll not accept objects. Now method takes `Class` type and I removed extra `getClass()`, and it is working fine – manikanta Sep 29 '11 at 15:28
  • @mrCoder: What objects would you want it to accept *other* than AnnotatedElement values, and what would you expect it to do with them? – Jon Skeet Sep 29 '11 at 16:08
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/3902/discussion-between-mrcoder-and-jon-skeet) – manikanta Sep 29 '11 at 16:11
  • @mrCoder: No, I'm afraid I don't do chat - it doesn't work well with my usage pattern. – Jon Skeet Sep 29 '11 at 16:13
  • No problem, I just clicked 'automatically move this discussion to chat' link out of curiosity (first time!). I m using `Class` as parameter – manikanta Sep 29 '11 at 16:24
3

First, see java.lang.annotation.Inherited.

Second, as others pointed out, your code is a bit different from your question.

Third, to answer your question..

I have encountered a similar need many times so I have written a short AnnotationUtil class to do this and some other similar things. Spring framework offers a similar AnnotationUtils class and I suppose dozen other packages today also contain pretty much this piece of code so you don't have to reinvent the wheel.

Anyway this may help you.

public static <T extends Annotation> T getAnnotation(Class<?> clazz, Class<T> annotationType) {
    T result = clazz.getAnnotation(annotationType);
    if (result == null) {
        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null) {
            return getAnnotation(superclass, annotationType);
        } else {
            return null;
        }
    } else {
        return result;
    }
}
JimmyB
  • 11,178
  • 1
  • 23
  • 42
lokori
  • 426
  • 5
  • 6
  • Yeah, I m using similar method. But this will not help in my case as I m calling `getClass()` again on the `Class` parameter. Thanks for the `java.lang.annotation.Inherited` tip. – manikanta Sep 29 '11 at 15:08
2

The o1.getClass() will give you object of type java.lang.Class, which doesn't have @Table annotation. I suppose you wanted o1.isAnnotationPresent(Table.class).

Eugene Kuleshov
  • 30,122
  • 5
  • 61
  • 63
1

In your code, o1, o2 and o3 are already the Class<?> objects on which you'll want to call isAnnotationPresent(Class<?>), you shouldn't call getClass() on them before, because at this stage, you'll call isAnnotationPresent(Class<?>)on the Class class itself, and not on your SomeEntity class...

Romain
  • 11,853
  • 3
  • 35
  • 54