For better debugging, I would often like to have:
Exception
at com.example.blah.Something.method()
at com.example.blah.Xyz.otherMethod()
at com.example.hello.World.foo()
at com.example.debug.version_3_8_0.debug_info_something.Hah.method() // synthetic method
at com.example.x.A.wrappingMethod()
The debug stack frame as shown above would be dynamically generated, just like a java.lang.reflect.Proxy
, except that I'd like to be in full control of the entire fully qualified method name that ends up on the proxy.
At the call site, I would do something silly and simple as this:
public void wrappingMethod() {
run("com.example.debug.version_3_8_0.debug_info_something.Hah.method()", () -> {
World.foo();
});
}
As you can see, the wrappingMethod()
is a real method that ends up on the stack trace, Hah.method()
is a dynamically generated method, whereas World.foo()
is again a real method.
Yes, I know this pollutes the already deep deep stack traces. Don't worry about it. I have my reasons.
Is there a (simple) way to do this or something similar as the above?
No need for code generation to solve this problem:
static void run(String name, Runnable runnable) {
try {
runnable.run();
} catch (Throwable throwable) {
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
StackTraceElement[] currentStackTrace = new Throwable().getStackTrace();
if (stackTraceElements != null && currentStackTrace != null) { // if disabled
int currentStackSize = currentStackStrace.length;
int currentFrame = stackTraceElements.length - currentStackSize - 1;
int methodIndex = name.lastIndexOf('.');
int argumentIndex = name.indexOf('(');
stackTraceElements[currentFrame] = new StackTraceElement(
name.substring(0, methodIndex),
name.substring(methodIndex + 1, argumentIndex),
null, // file name is optional
-1); // line number is optional
throwable.setStackTrace(stackTraceElements);
}
throw throwable;
}
}
With code generation, you could add a method with the name, redefine the call site within the method, unwind the frame and call the generated method but this would be much more work and would never be equally stable.
This strategy is a rather common approach in testing frameworks, we do it a lot in Mockito and also other utilities like JRebel do it to hide their magic by rewriting exception stack frames.
When Java 9 is used, it would be more efficient to do such manipulations using the Stack Walker API.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With