isAnnotationPresent() return false when used with super type reference in Java
Asked Answered
G

4

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?

Gery answered 29/9, 2011 at 14:40 Comment(0)
O
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));
Ozalid answered 29/9, 2011 at 14:48 Comment(14)
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.Gery
@mrCoder typical "abuse of copy-paste" issue... Everyone falls into this one :)Ravin
@Ravin Yeah, quite some time we can't help with that. ha haGery
But to get the annotation info when referring using Object? Is it possible? the last case in my OP. ThanksGery
@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).Ravin
@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?Ozalid
Previous code accepts Object and at that time getClass() is used. Later I've changed to Class, but missed to remove the getClass()Gery
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, ...)Gery
@mrCoder: Can you change it to some(AnnotatedElement o) instead? Then just use System.out.println(o.isAnnotationPresent(Table.class));Ozalid
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 fineGery
@mrCoder: What objects would you want it to accept other than AnnotatedElement values, and what would you expect it to do with them?Ozalid
let us continue this discussion in chatGery
@mrCoder: No, I'm afraid I don't do chat - it doesn't work well with my usage pattern.Ozalid
No problem, I just clicked 'automatically move this discussion to chat' link out of curiosity (first time!). I m using Class as parameterGery
M
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;
    }
}
Musicianship answered 29/9, 2011 at 15:1 Comment(1)
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.Gery
D
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).

Doug answered 29/9, 2011 at 14:50 Comment(0)
R
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...

Ravin answered 29/9, 2011 at 14:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.