Pregunta

For understanding of the Java annotations I tried some hands on and got few doubts, even though looking at execution I am still confused. Here is what I am doing. Define a Annotation

@Retention(RetentionPolicy.CLASS)
@Target(value=ElementType.TYPE)
public @interface Command {

}

Now I initialize the commands

       Reflections reflections = new Reflections(CMDS_PACKAGE);
       Set<Class<?>> allClasses = reflections.getTypesAnnotatedWith(Command.class); // line 2

        for (Class clazz : allClasses) {
            MYCommand cmd = (MYCommand) clazz.newInstance();
            System.out.println(cmd.getClass().getAnnotation(Command.class));// line 6
            log.info("loading Command [ {} ]", clazz.getCanonicalName());
        }

when I run the program line 6 displays null. When the policy is RetentionPolicy.RUNTIME line 6 displays the correct Command.

During this process the line 2 is still giving me correct Annotated class irrespective of policy. So does it mean that the Reflection Library is ignoring the RetentionPolicy

I am really confused even though reading most of tutorials.

The question for me actually is that , why is this different behaviour? When annotated with RetentionPolicy.CLASS policy It should not have given me at runtime. Is my understanding wrong or can anyone please share there valuable inputs on the understanding of these both.

¿Fue útil?

Solución

Yes, the Reflections library (not Reflection, but Reflection*s*) does ignore the visibility of annotations by default. This can be changed using the org.reflections.adapters.JavassistAdapter#includeInvisibleTag flag. Something like:

JavassistAdapter mdAdapter = new JavassistAdapter();
mdAdapter.includeInvisibleTag = false;

new Reflections(new ConfigurationBuilder()
    ...
    .setMetadataAdapter(mdAdapter)
    ...

Another option would be to use the JavaReflectionAdapter instead.

HTH

Otros consejos

In the first place, the RetentionPolicy dictates what a conforming compiler has to do. Annotations with RetentionPolicy.SOURCE do not make it into the class file while the other two, RetentionPolicy.CLASS and RetentionPolicy.RUNTIME, are stored within the class file but using different attributes to allow to make a distinction between them when reading the class file.

The documentation of RetentionPolicy.CLASS says:

Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.

Here, the responsibility is clearly documented, the VM shall not retain them and the Reflection API built into the JRE conforms to it. Though “need not be retained” does not sound like a strong requirement.

But 3rd party libraries like the Reflection Library you are using are free to implement whatever they want when parsing a class file. Since the documentation for the method you have called simply says: “get types annotated with a given annotation”, the behavior isn’t wrong as the type has that annotation.

And you are able to find out the RetentionPolicy of that Annotation even before invoking that method by analyzing the Annotations of the Annotation. So it makes no sense invoking the method when you already know that the annotation has the RetentionPolicy.CLASS and then bother because the method does something instead of nothing.

But, of course, it would be better if that behavior was documented completely. So you might ask the author of that 3rd party library to improve the documentation.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top