48

How can I retrieve the value of an annotation on the annotated method??

I have:

@myAnnotation(attribute1 = value1, attibute2 = value2)
public void myMethod()
{
  //I want to get value1 here
}
Tim Büthe
  • 62,884
  • 17
  • 92
  • 129
Diego Dias
  • 21,634
  • 6
  • 33
  • 36
  • Can you provide more detail on what you're trying to accomplish? – Carl Nov 26 '09 at 19:16
  • It's just as I said, I want to use the value of attribute1 without having to repeat it on the code – Diego Dias Nov 26 '09 at 19:21
  • 1
    That's not really an effective programming method. There's no advantage here to having the values set in an annotation as opposed to being set in final variables inside the code, or being set in final static variables outside the method. – Jherico Nov 26 '09 at 22:38
  • I know that this is late but can you please share the definition of your @MyAnnotation interface as well? So the question has more context. Thanks – Valerio Bozz Jan 17 '23 at 12:20

4 Answers4

62
  1. Obtain Method instance.
  2. Obtain annotation.
  3. Obtain annotation attribute value.

Something like:

Method m = getClass().getMethod("myMethod");
MyAnnotation a = m.getAnnotation(MyAnnotation.class);
MyValueType value1 = a.attribute1();

You'll need to catch / handle the appropriate exceptions, of course. The above assumes you are indeed retrieving method from the current class (replace getClass() with Class.forName() otherwise) and the method in question is public (use getDeclaredMethods() if that's not the case)

ChssPly76
  • 99,456
  • 24
  • 206
  • 195
  • shouldn't it be "MyValueType value1 = a.getAttribute1();" – DJ. Nov 26 '09 at 19:27
  • Regarding step 1, obtain the method instance using the following solution: http://stackoverflow.com/a/5891326/435605 – AlikElzin-kilaka Apr 27 '15 at 13:20
  • Please note that a method name might change by obfuscation or even compiler specific optimizations, in the end it is absolutely not guaranteed to be referenced by name during runtime. – Thomas Jul 21 '16 at 08:33
25

Two important things:

  • There is no way to get the current method, e.g. there is no getMethod() such as getClass(). Therefore, the method accessing its own annotation would need to know its own name.
  • The retention policy of the annotation must be set to RUNTIME, so you can access the annotation at runtime. The default is compile-time, which means annotations are available in the class file, but cannot be accessed at runtime using reflection.

Full example:

@Retention(RetentionPolicy.RUNTIME)
public static @interface MyAnnotation {
    String value1();

    int value2();
}

@Test
@MyAnnotation(value1 = "Foo", value2 = 1337)
public void testAnnotation() throws Exception {
    Method[] methods = getClass().getMethods();
    Method method = methods[0];
    assertEquals("testAnnotation", method.getName());
    MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
    assertEquals("Foo", annotation.value1());
    assertEquals(1337, annotation.value2());
}
mhaller
  • 14,122
  • 1
  • 42
  • 61
  • 5
    There is a way to get current method. Either `Thread.currentThread().getStackTrace()[2].getMethodName()` or `new Throwable().fillInStackTrace().getStackTrace()[0].getMethodName()` should do it. – ChssPly76 Nov 26 '09 at 19:48
  • 1
    @ChssPly76, building a stacktrace isn't entirely reliable, as the javadocs mention: "Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information [...] is permitted to return a zero-length array from this method." – gustafc Nov 27 '09 at 07:21
  • Obtain the method instance using the following solution: http://stackoverflow.com/a/5891326/435605 – AlikElzin-kilaka Apr 27 '15 at 13:21
2

To get the current method, try using this code:

Thread.currentThread().getStackTrace()[1].getClassName().toString()+\".\"+Thread.currentThread().getStackTrace()[1].getMethodName().toString()
Joe
  • 4,877
  • 5
  • 30
  • 51
s s
  • 286
  • 2
  • 14
1

@mhaller: a bit too long for a comment on your post. Obviously would need further refinement to deal with overloaded methods, but it is not impossible.:

import java.lang.reflect.Method;

public class Hack {
    public static void main (String[] args) {
        (new Hack()).foobar();
    }
    public void foobar () {
        Method here = getCurrentMethod(this);
        System.out.format("And here we are: %s\n", here);
    }
    public static final Method getCurrentMethod(Object o) {
        String s = Thread.currentThread().getStackTrace()[2].getMethodName();
        Method cm = null;
        for(Method m : o.getClass().getMethods()){
            if(m.getName().equals(s)){
                cm = m; break;
            }
        }
        return cm;
    }
}

[edit: credit/thanks to Alexandr Priymak for spotting the error in main()]

alphazero
  • 27,094
  • 3
  • 30
  • 26
  • 4
    I have a feeling that if you actually do this in production code, it summons the Great Old Ones to devour your very soul! – Skip Head Nov 26 '09 at 21:14
  • @Skip Head - why? There are two things to be careful about here - (1) array index **in theory** may be different from 2 on some JVMs but that's easy to work around by walking through whole trace; (2) this won't work for overloaded methods; you can do some black magic with javassist to guess the right one based on line number but that really is somewhat iffy. Other then that, though, it works perfectly - how do you think stack traces work? – ChssPly76 Nov 26 '09 at 21:26
  • @ChssPly76: No need to walk the whole trace. The trace method starts at top and walks until it finds itself. And the caller is the next. – alphazero Nov 26 '09 at 22:26
  • @alphazero - you'd think so, but no :-) That is, this is **normally** the case but it's not spec'ed anywhere AFAIK, meaning you can have a JVM implementation that behaves differently (e.g. the method in question may be in 2nd or even 1st argument of stack trace array) – ChssPly76 Nov 26 '09 at 22:38