请参阅调用方法的java注释
假设我遇到这样的情况:请参阅调用方法的java注释,java,reflection,annotations,Java,Reflection,Annotations,假设我遇到这样的情况: public String method(String s) { return stringForThisVisibility(s, EnumVisibility.PUBLIC); } @VisibilityLevel(value = EnumVisibility.PUBLIC) public String method(String s) { return stringForThisVisibility(s); } 我想用这样的注释替换它: publ
public String method(String s) {
return stringForThisVisibility(s, EnumVisibility.PUBLIC);
}
@VisibilityLevel(value = EnumVisibility.PUBLIC)
public String method(String s) {
return stringForThisVisibility(s);
}
我想用这样的注释替换它:
public String method(String s) {
return stringForThisVisibility(s, EnumVisibility.PUBLIC);
}
@VisibilityLevel(value = EnumVisibility.PUBLIC)
public String method(String s) {
return stringForThisVisibility(s);
}
这似乎是一个更好、更清晰的解决方案,但我需要stringForThisVisibility方法通过某种反射来了解@VisibilityLevel的值。可能吗?我可以看到调用stringForThisVisibility的方法上的注释吗?可以。
类似于
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
Class callerClass = Class.forName(stack[stack.length-2].getClassName());
callerClass.isAnnotationPresent(...)
上面的代码查找类上的注释。您可以组合类名和方法名(也可以来自堆栈跟踪元素),然后查看方法。请注意,这非常慢。您需要获取表示调用stringForThisVisibility的方法的对象。不幸的是,Java没有提供这种现成的功能
但是,我们仍然可以通过返回的信息获得方法
。该方法返回一个对象数组。每个stackTraceeElement
对象告诉我们三件事:
- 类的名称()
- 方法的名称()
- 行号()
这可能需要一些实验,但您应该找到该数组中的哪个索引表示您感兴趣的方法(它可能是数组中的第一个、第二个或第三个stackTraceeElement
)
获得所需的StackTraceeElement
后,可以使用题为的问题中的技术获取其相应的方法
对象。即使该类有多个方法使用该方法名,该技术仍将保留word。如果您不担心这种情况,可以使用更简单的技术
拥有方法
对象后,只需调用以下类即可。:
/**
* 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();
}
}
你可以说:
方法me=(新的Util.MethodNameHelper(){}).getMethod()
我在该类中广泛使用了getName()调用。在我的机器上,这些匿名类实例化加上方法调用往往需要花费1500纳秒。在我的性能测试中,StackElement步行方法在我的机器上的成本大约是30倍(47000 ns) 这也是我知道的唯一解决办法。并不是说它不能保证在所有情况下都能工作:如果加载被调用类的类加载器不知道调用类(并且它的父类加载器都不知道),那么对class.forName()
的调用将失败。这种技术是脆弱的(如果您的方法不是直接从带注释的方法调用的,该怎么办?您需要在堆栈中循环。如果注释在超类方法上而不是直接在调用方法上,该怎么办?您需要在超类上循环…)如果Philipp是对的,它可能会在复杂环境中出错(j2ee?osgi?)。它的速度也非常慢。您可以选择使用ThreadLocal标记的解决方案,并在调用该方法之前设置标记,但这看起来也很奇怪。如果您能准确描述您要做的事情,可能会找到一个优雅的解决方案