获取调用方法(java.lang.reflect.Method)

我想得到调用方法java.lang.reflect.Method不是方法的名称。

以下是如何获取调用者类的示例。

 // find the callers class Thread t = Thread.getCurrentThread(); Class klass = Class.forName(t.getStackTrace()[2].getClassName()); // do something with the class (like processing its annotations) ... 

它仅用于测试目的!

如果它只是用于测试,那么这可能会起作用。 它假定类文件可以通过调用类的ClassLoader访问,并且类文件是用调试符号编译的(我希望它们用于测试!)。 此代码依赖于ASM字节码库 。

 public static Method getMethod(final StackTraceElement stackTraceElement) throws Exception { final String stackTraceClassName = stackTraceElement.getClassName(); final String stackTraceMethodName = stackTraceElement.getMethodName(); final int stackTraceLineNumber = stackTraceElement.getLineNumber(); Class stackTraceClass = Class.forName(stackTraceClassName); // I am only using AtomicReference as a container to dump a String into, feel free to ignore it for now final AtomicReference methodDescriptorReference = new AtomicReference(); String classFileResourceName = "/" + stackTraceClassName.replaceAll("\\.", "/") + ".class"; InputStream classFileStream = stackTraceClass.getResourceAsStream(classFileResourceName); if (classFileStream == null) { throw new RuntimeException("Could not acquire the class file containing for the calling class"); } try { ClassReader classReader = new ClassReader(classFileStream); classReader.accept( new EmptyVisitor() { @Override public MethodVisitor visitMethod(int access, final String name, final String desc, String signature, String[] exceptions) { if (!name.equals(stackTraceMethodName)) { return null; } return new EmptyVisitor() { @Override public void visitLineNumber(int line, Label start) { if (line == stackTraceLineNumber) { methodDescriptorReference.set(desc); } } }; } }, 0 ); } finally { classFileStream.close(); } String methodDescriptor = methodDescriptorReference.get(); if (methodDescriptor == null) { throw new RuntimeException("Could not find line " + stackTraceLineNumber); } for (Method method : stackTraceClass.getMethods()) { if (stackTraceMethodName.equals(method.getName()) && methodDescriptor.equals(Type.getMethodDescriptor(method))) { return method; } } throw new RuntimeException("Could not find the calling method"); } 

我们几乎可以到达那里,这是一种适用于许多情况的方法。 问题是:如果存在重载方法(多个具有相同名称的方法),它将无法可靠地工作。 遗憾的是,堆栈跟踪不提供参数。

 private static Method getCallingMethod() throws ClassNotFoundException{ final Thread t = Thread.currentThread(); final StackTraceElement[] stackTrace = t.getStackTrace(); final StackTraceElement ste = stackTrace[2]; final String methodName = ste.getMethodName(); final String className = ste.getClassName(); Class kls = Class.forName(className); do{ for(final Method candidate : kls.getDeclaredMethods()){ if(candidate.getName().equals(methodName)){ return candidate; } } kls = kls.getSuperclass(); } while(kls != null); return null; } 

测试代码:

 public static void main(final String[] args) throws Exception{ System.out.println(getCallingMethod()); } 

输出:

public static void foo.bar.Phleem.main(java.lang.String [])抛出java.lang.Exception


好的,这是使用ASM的解决方案。 几乎适用于所有情况:

 private static Method getCallingMethod() throws ClassNotFoundException, IOException{ final Thread t = Thread.currentThread(); final StackTraceElement[] stackTrace = t.getStackTrace(); final StackTraceElement ste = stackTrace[2]; final String methodName = ste.getMethodName(); final int lineNumber = ste.getLineNumber(); final String className = ste.getClassName(); final Class kls = Class.forName(className); final ClassReader cr = new ClassReader(className); final EmptyVisitor empty = new EmptyVisitor(); final AtomicReference holder = new AtomicReference(); cr.accept(new ClassAdapter(empty){ @Override public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions){ return name.equals(methodName) ? new MethodAdapter(empty){ @Override public void visitLineNumber(final int line, final Label start){ if(line >= lineNumber && holder.get() == null){ final Type[] argumentTypes = Type.getArgumentTypes(desc); final Class[] argumentClasses = new Class[argumentTypes.length]; try{ for(int i = 0; i < argumentTypes.length; i++){ final Type type = argumentTypes[i]; final String dd = type.getDescriptor(); argumentClasses[i] = getClassFromType(type); } holder.set(kls.getDeclaredMethod(methodName, argumentClasses)); } catch(final ClassNotFoundException e){ throw new IllegalStateException(e); } catch(final SecurityException e){ throw new IllegalStateException(e); } catch(final NoSuchMethodException e){ throw new IllegalStateException(e); } } super.visitLineNumber(line, start); } private Class getClassFromType(final Type type) throws ClassNotFoundException{ Class javaType; final String descriptor = type.getDescriptor(); if(type.equals(Type.INT_TYPE)){ javaType = Integer.TYPE; } else if(type.equals(Type.LONG_TYPE)){ javaType = Long.TYPE; } else if(type.equals(Type.DOUBLE_TYPE)){ javaType = Double.TYPE; } else if(type.equals(Type.FLOAT_TYPE)){ javaType = Float.TYPE; } else if(type.equals(Type.BOOLEAN_TYPE)){ javaType = Boolean.TYPE; } else if(type.equals(Type.BYTE_TYPE)){ javaType = Byte.TYPE; } else if(type.equals(Type.CHAR_TYPE)){ javaType = Character.TYPE; } else if(type.equals(Type.SHORT_TYPE)){ javaType = Short.TYPE; } else if(descriptor.startsWith("[")){ final Class elementType = getClassFromType(type.getElementType()); javaType = Array.newInstance(elementType, 0).getClass(); } else{ javaType = Class.forName(type.getClassName()); } return javaType; } } : null; } }, 0); return holder.get(); } 

我会留给你把它重构成可读的东西。 如果调用方法的签名包含原始数组或多维数组,它将无法工作。 显然,只有在类文件包含行号时才有效。

Argghh,我工作了很长时间,然后我发现有人提出了一个几乎相同的解决方案! 无论如何,我会离开我的,因为我是独立开发的。

很容易:首先获取相应的Class对象,然后使用Class.getMethod(String name,params...)

点击这里查看javadoc

 public class GetMethod { public static void main(String[] args){ new GetMethod().checkMethod(); } public void checkMethod(){ Thread t=Thread.currentThread(); StackTraceElement element=t.getStackTrace()[1]; System.out.println(element.getClassName()); System.out.println(element.getMethodName()); try{ Method m=Class.forName(element.getClassName()).getMethod(element.getMethodName(),null); System.out.println("Method: " + m.getName()); }catch (Exception e) { e.printStackTrace(); } } } 

希望有帮助….

以下是Sean Patrick Floyd发布的从ASM类型获取Java类的方法的修改版本。 它解决了多维数组的问题以及其他类加载器加载的类的另一个问题。

 public static Class getClassFromType(Class clazz, final Type type) throws ClassNotFoundException{ Class javaType = null; switch( type.getSort() ) { case Type.VOID : javaType = Void.TYPE; break; case Type.BOOLEAN : javaType = Boolean.TYPE; break; case Type.CHAR : javaType = Character.TYPE; break; case Type.BYTE : javaType = Byte.TYPE; break; case Type.SHORT : javaType = Short.TYPE; break; case Type.INT : javaType = Integer.TYPE; break; case Type.FLOAT : javaType = Float.TYPE; break; case Type.LONG : javaType = Long.TYPE; break; case Type.DOUBLE : javaType = Double.TYPE; break; case Type.ARRAY : javaType = Array.newInstance( getClassFromType( clazz, type.getElementType()), new int[type.getDimensions()] ).getClass(); break; case Type.OBJECT : javaType = Class.forName( type.getClassName(), false, clazz.getClassLoader() ); break; } if ( javaType != null ) return javaType; throw new ClassNotFoundException( "Couldn't find class for type " + type ); }