views:

82

answers:

2

This puzzles me. I have a class with a custom annotation and I can't seem to verify that the annotation is present. What am I doing wrong here? If I run MyOperationTest (see below), I get this as a result:

implements Library.Operation: true
has @Library.Marker: false
Tada!

Library.java:

package com.example.gotchas;

public class Library {
    private Library() {}

    public @interface Marker {}

    public interface Operation {
        public void execute(); 
    }
}

MyOperation.java:

package com.example.gotchas;

@Library.Marker
public class MyOperation implements Library.Operation {
    @Override public void execute() {
        System.out.println("Tada!");
    }
}

MyOperationTest.java:

package com.example.gotchas;

public class MyOperationTest {
    static public void main(String[] args)
    {
        try {
            Class<?> cl = Class.forName("com.example.gotchas.MyOperation");
            boolean implementsLibraryOperation =
                Library.Operation.class.isAssignableFrom(cl);
            boolean hasLibraryMarker =
                cl.isAnnotationPresent(Library.Marker.class);
            System.out.println("implements Library.Operation: "
                    +implementsLibraryOperation);
            System.out.println("has @Library.Marker: "+hasLibraryMarker);
            if (implementsLibraryOperation)
            {
                Class<? extends Library.Operation> opClass = 
                    cl.asSubclass(Library.Operation.class); 
                Library.Operation op = opClass.newInstance();
                op.execute();
            }
        }
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        catch (InstantiationException e) {
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
+8  A: 

You have to define @Retention for your annotation:

@Retention(RetentionPolicy.RUNTIME)
public @interface Marker {}

Otherwise the annotation is not retained at runtime.

(You can also add explicit @Target(ElementType.TYPE) if you want to limit the usage of your annotation only on classes)

As a sidenote - it is not a common practice to define annotations as inner classes.

Bozho
Agreed. By default the annotation is not retained through runtime... after compile-time it's dropped. Hence when you run your test code, the annotation is no longer part of the compiled code.
RonU
More detail in [RetentionPolicy javadoc](http://download.oracle.com/javase/6/docs/api/java/lang/annotation/RetentionPolicy.html): *RUNTIME - Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, **so they may be read reflectively**.*
BalusC
ah! thanks!!!!!
Jason S
+1  A: 

By default, annotation retention policy is CLASS, which does not make your annotation available to reflection. You should qualify it when declaring the annotation.

kohomologie