Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

See java annotations on calling method

Let's say I have a situation like this:

public String method(String s) {
    return stringForThisVisibility(s, EnumVisibility.PUBLIC);
}

and I want to replace it with an annotation like this:

@VisibilityLevel(value = EnumVisibility.PUBLIC)
public String method(String s) {
    return stringForThisVisibility(s);
}

This seems to be a better and more clear solution, but i need for stringForThisVisibility method to know value of @VisibilityLevel with some kind of reflection. Is that possible? Can I see the annotations on the method calling stringForThisVisibility?

like image 874
Fabio Avatar asked Dec 18 '11 11:12

Fabio


People also ask

How do you check if a method has an annotation?

The isAnnotation() method is used to check whether a class object is an annotation. The isAnnotation() method has no parameters and returns a boolean value. If the return value is true , then the class object is an annotation. If the return value is false , then the class object is not an annotation.

Can Java annotations have methods?

Annotations can be applied to declarations: declarations of classes, fields, methods, and other program elements. When used on a declaration, each annotation often appears, by convention, on its own line. As of the Java SE 8 release, annotations can also be applied to the use of types.


2 Answers

With the following class:

 /**
   * Proper use of this class is
   *     String testName = (new Util.MethodNameHelper(){}).getName();
   *  or
   *     Method me = (new Util.MethodNameHelper(){}).getMethod();
   * the anonymous class allows easy access to the method name of the enclosing scope.
   */
  public static class MethodNameHelper {
    public String getName() {
      final Method myMethod = this.getClass().getEnclosingMethod();
      if (null == myMethod) {
        // This happens when we are non-anonymously instantiated
        return this.getClass().getSimpleName() + ".unknown()"; // return a less useful string
      }
      final String className = myMethod.getDeclaringClass().getSimpleName();
      return className + "." + myMethod.getName() + "()";
    }

    public Method getMethod() {
      return this.getClass().getEnclosingMethod();
    }
  }

One can call: Method me = (new Util.MethodNameHelper(){}).getMethod();

I make extensive use of the getName() call in that class. On my machine those anonymous class instantiations plus method invocations tend to cost about 1500 ns each. The StackElement walking approach costs about 30 times as much (47000 ns) on my machine in my performance test.

like image 200
Jim Avatar answered Oct 24 '22 18:10

Jim


You need to obtain the Method object that represents the method that called stringForThisVisibility. Unfortunately, Java doesn't offer this functionality out of the box.

However, we can still obtain the Method via the information returned by Thread.currentThread().getStackTrace(). That method returns an array of StackTraceElement objects. Each StackTraceElement object tells us three things:

  • The name of the class (getClassName())
  • The name of the method (getMethodName())
  • The line number (getLineNumber())

It may take some experimentation, but you should find which index in that array represents the method you're interested in (it will probably be the first, second or third StackTraceElement in the array).

Once you have the desired StackTraceElement, you can obtain its corresponding Method object using the technique in my answer to the question entitled "Get caller's method (java.lang.reflect.Method)". That technique will still word, even if the class has more than one method with that method name. There are simpler techniques if you're not worried about that scenario.

Once you have the Method object, it's just a matter of calling method.getAnnotation(VisibilityLevel.class).

like image 26
Adam Paynter Avatar answered Oct 24 '22 18:10

Adam Paynter