What do I have
I had set an AspectJ joint point for some specific methods in order to be able to measure their execution time. I never intercept anything in the code flow (so we can call this a "read-only" type of weaved code). The corresponding code looks like:
@Around("execution (* my.package.myclass..*(..)) && @annotation(my.another.package.Monitored)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
Object returnObject = null;
long startTime = System.currentTimeMillis();
try {
returnObject = joinPoint.proceed();
} catch (Throwable throwable) {
System.out.println("Intercepted exception " + throwable.getClass().getName() + ": " + throwable.getMessage());
throw throwable; //<---- this does the jail-breaking
} finally {
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime;
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Monitored annotation = method.getAnnotation(Monitored.class);
//do some more logic as logging etc.
}
return returnObject;
}
Also in the application code itself I have stuff like:
try {
//this is a monitored call:
my.package.myclass.doStuff();
} catch (Throwable anyException) {
//log stuff
//& return default non-null entity
}
Which means I gracefully handle any possible exception at that layer and disallow it to be thrown to the upper layers.
What went wrong
If there is no exceptions thrown by the application code, there are no issues and all the logic works fine - time is measured, logged and tracked. But if there is an exception thrown by the application it escapes the application handler which I posted above and is thrown to the upper layers.
In the debugger I see that it is done by the line which throws throwable from my aspected handler. And this is something I do not understand. Obviously, if I remove throwing an exception from there it becomes even worse since now the entity will be null and the whole application flow would be broken
Question
How to properly deal with exception so to log them happened together with conducting all measuring business and do not allow them to jail-break?
Just as for Nándor it works for me when trying to replicate your situation, even with LTW. Here is a stand-alone example:
Java driver application:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
try {
new Application().doSomething();
}
catch (Throwable t) {
System.out.println("Caught & handled exception: " + t);
}
}
public void doSomething() throws InterruptedException {
Thread.sleep(100);
throw new RuntimeException("Oops!");
}
}
Aspect:
package de.scrum_master.aspect;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
@Aspect
public class RuntimeLogger {
@Around("execution(!static * *(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
Object returnObject = null;
long startTime = System.currentTimeMillis();
try {
returnObject = joinPoint.proceed();
} catch (Throwable throwable) {
System.out.println("Intercepted exception " + throwable.getClass().getName() + ": " + throwable.getMessage());
throw throwable; //<---- this does the jail-breaking
} finally {
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime;
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println(elapsedTime + " " + method);
}
return returnObject;
}
}
Console log:
Intercepted exception java.lang.RuntimeException: Oops!
100 public void de.scrum_master.app.Application.doSomething() throws java.lang.InterruptedException
Caught & handled exception: java.lang.RuntimeException: Oops!
Here on StackOverflow a while ago someone was asking for a way to generate some kind of uncatchable "Chuck Norris exception" and I created one for him here using AspectJ. So, just guessing, do you maybe have another aspect or advice anywhere in your code which (re-)throws the exception in question fron a before() : handler() advice? For instance, if you add this to your aspect:
@Before("handler(*) && args(t)")
public void enforceThrow(Throwable t) throws Throwable {
System.out.println("Let's see if we can break the jail...");
throw t;
}
Then the console log turns into:
Let's see if we can break the jail...
100 public void de.scrum_master.app.Application.doSomething() throws java.lang.InterruptedException
Let's see if we can break the jail...
Exception in thread "main" java.lang.RuntimeException: Oops!
at de.scrum_master.app.Application.doSomething_aroundBody0(Application.java:15)
at de.scrum_master.app.Application$AjcClosure1.run(Application.java:1)
at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149)
at de.scrum_master.aspect.RuntimeLogger.logExecutionTime(RuntimeLogger.aj:18)
at de.scrum_master.app.Application.doSomething(Application.java:14)
at de.scrum_master.app.Application.main(Application.java:6)
This is pretty much similar to the effect you are describing.
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