See java annotations on calling method

只谈情不闲聊 提交于 2020-01-01 05:14:52

问题


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?


回答1:


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).




回答2:


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.




回答3:


yes you could. something along the lines of

StackTraceElement[] stack = Thread.currentThread().getStackTrace();
Class callerClass = Class.forName(stack[stack.length-2].getClassName());
callerClass.isAnnotationPresent(...)

the code above looks for annotations on the class. you could combine class name and method name (also from the stack trace element) and go look at the method. do note that this is extremely slow.



来源:https://stackoverflow.com/questions/8551287/see-java-annotations-on-calling-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!