Reputation: 167
I have service calls in my application that make remote network calls to other services as well as DB calls. Spring Boot has good support for rolling back bad transactions with @Transactional
, but I wanted to know if I could define a custom rollback procedure using an annotation.
I would need to rollback the data on the other services as well as the database.
In code, I could do it like this:
@Transactional
public void doSomethingComplicated() {
try {
srvcOne.makeRemoteNetworkCall();
srvcTwo.makeDatabaseCall();
} catch(Exception e) {
srvcOne.rollBackNetworkCall();
}
}
but I was hoping I could do something like this:
@Transactional
@MyCustomRollbackListener(handler = MyCustomRollBackHandler.class)
public void doSomethingComplicated() {
srvcOne.makeRemoteNetworkCall();
srvcTwo.makeDatabaseCall();
}
and in the handler:
public class MyCustomRollBackHandler {
public void handleRollback() {
srvcOne.rollBackNetworkCall();
}
}
I implemented a global exception listener and I am able to get the class the exception came from, but I have no way to get the method and to retrieve any annotations on it. Here is my initial attempt:
@ControllerAdvice
public class RollbackExceptionListener{
private static final Logger logger = LoggerFactory.getLogger(RollbackExceptionListener.class);
@ExceptionHandler(Exception.class)
public void lookForAnnotationClassForException(final Exception exception) {
logger.error("Exception thrown", exception);
final StackTraceElement topElement = exception.getStackTrace()[0];
final Class callingClass = topElement.getClass();
final String methodName = topElement.getMethodName();
try {
// Can't get the method with just the name, need to
// know the params as well.
final Method method = callingClass.getMethod(methodName);
// Retrieve the annotation on the method and call the handler
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
Is there anyway to do something like this?
Upvotes: 1
Views: 310
Reputation: 4276
Arguments are not part of the Stacktrace. If the method is unique, i.e. not overloaded, you can probably find it with getMethods()
? Something else that comes to mind, maybe you can look at Aspects to wrap the method in some handler before it is executed. Can be done either at compile time or runtime.
The aspect can do the rollback itself, it can enrich the exception with the information you need, or it can set some ThreadLocal
variable with the handler class that was defined in the method before re-throwing the exception. You can then get this value from the ThreadLocal
at the point where you catch the exception.
Upvotes: 1