Search code examples
javadebuggingloggingutility

Looking for Java method capable of identifying which method it is called by


I have been working on a small logging/debug library for my Java projects. I know there are many good ones already out there but I want to learn from doing one myself.

One method I want to have as part of this library is the ability to find out which method you are in at any one time, similar to __func__ in C++. Most of the time it'd be fine to just use the StackTrace to find this, since you often don't need more than the name (and/or declaring class) of the method, but I want to have the ability to get the method as an instance of the java.lang.reflect.Method

The easiest way of doing this is by simply doing

Method currentMethod = new Object() {}.getClass().getEnclosingMethod();

which will work just fine, but I can't figure out a way to do the same without creating that 'new Object() {}' within the method itself. Ideally I'd prefer if I could make a simple

Method currentMethod = _method();

to get the same result but with my current approach it'd just get me the Method-instance of _method itself.

Is there any known method to achieve this? If there isn't that's fine, but it'd be nice to have one.

EDIT: A lot of suggestions I receive, such as this post, provide mostly answers that provide you with the NAME of the method. It would be possible to use that (and the Class info gained in the same way) to find the Method, but only if the class in question has only one method with that name. Methods with the same name but different arguments cannot be identified with this!


Solution

  • This can be done using a StackWalker (since Java 9). It does not directly provide a Method but enough information to create one. Here the basic idea, can be improved (e.g. better Exception(s)):

    import java.lang.StackWalker.Option;
    import java.lang.StackWalker.StackFrame;
    import java.lang.reflect.Method;
    
    public class MethodFinder {
    
        public static Method method() {
            return StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).walk(stream -> 
                stream
                .filter(MethodFinder::notThisClass)
                .findFirst()
                .map(MethodFinder::frameToMethod))
                .orElseThrow();
        }
        
        private static boolean notThisClass(StackFrame frame) {
            return frame.getDeclaringClass() != MethodFinder.class;
        }
        
        private static Method frameToMethod(StackFrame frame) {
            var cl = frame.getDeclaringClass();
            try {
                return cl.getDeclaredMethod(frame.getMethodName(), frame.getMethodType().parameterArray());
            } catch (NoSuchMethodException | SecurityException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
    

    To be used like Method myself = MethodFinder.method().