Catch Spring runtime exception with Spring AOP - java

For logging purposes, we're trying to catch various Spring's runtime exceptions via Spring's own AOP and I must say I've been unsuccessful, so I would appreciate any ideas as to how to approach this.
I've tried something like this:
#Aspect
#Component
public class SomeAspect {
#AfterThrowing(pointcut = "execution(* org.springframwork.oxm..*(..))", throwing = "exception")
#Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public void adviseSpringErrorEvents(JoinPoint joinPoint, final UnmarshallingFailureException exception) throws Throwable {
LOG.debug(this.getClass().getSimpleName() + " - Error message advice fired on method: " + joinPoint.getSignature().getName());
}
}
The class is autoproxied and the rest of the advice in the aspect class correctly fire, so there has to be a problem with the AspectJ expression.
UPDATE: The code inside the method does not run and it is not my intention to catch the exception in the advice.
Any ideas? Thx in advance.
P.S. Spring framework version is 3.0.6.

Here are a couple of things that stand out to me:
Your point cut is for the spring package that the exception you are trying to catch it is in, it should be where you are trying to join execution(* com.mypackage..*(..)).
You are throwing throwable but you do not need to declare anything being thrown. The exception being advised of will not propagate through this code.
Things to try:
Expand your exception parameter to Exception. Maybe the exception you are looking for is in a different hierarchy.
Widen the pointcut to * package level - but probably best not to do both 1 and 2 at the same time.
Increase logging to a more severe level to be sure it is not getting gobbled by your logging framework.

Related

Patterns for exception handling in Spring Boot using beans or AOP

I have a Spring Boot server application where exceptions are caught, logged and handled when possible and when not possible they are handled by #ControllerAdvice as the last resort.
I want to add more logic for exception handling, for example, sending a metric to a monitoring solution on each exception. For example there's a Spring bean MetricsBean which is a service which sends metrics. Using MetricsBean is easy for errors which are handled by #ControllerAdvice because it's also a Spring bean.
However using MetricsBean is not as straightforward in such code:
try {
// business logic
} catch (Exception ex) {
logger.error(ex)
}
because that would mean manually autowiring MetricsBean into each service class. Also logger object is not a Spring bean.
So I have a dilemma how do I send a metric from inside or around logger.error() method when the logger class itself is not a Spring bean. I'm wondering what the best practice is in such cases. Here're some of the options:
Should logger also be a Spring bean? (seems tedious and error-prone)
Should there be a custom Exception extending class which would be a Spring bean and will send a metric inside its constructor? (seems tedious and error-prone)
Should Spring AOP be used with the pointcut being logger.error() method?
I'm surprised that there's not an established solution for this pattern for such an established framework as Spring (most of the solutions focus on handling errors in #ControllerAdvice).
I'd like the solution to be as generic as possible (point 3 seems to win there) but perhaps there's a pattern which I'm missing.
Not sure if it is the best practice but I would use a UtilityClass as a facade exposing a static method. In that method, wire the metrics registry using Metrics.globalRegistry to avoid injection. This will avoid coupling the metric details from where it is used.
You can then either invoke the static method everywhere you are handling an exception (so besides logger.error(ex)) or combine this with your third option with the pointcut.
Simple example:
#UtilityClass
public class ExceptionUtility {
public static void handleException(Throwable throwable) {
Counter.builder("some.name.exception")
.tag("name", throwable.getClass().getName())
.register(Metrics.globalRegistry)
.increment();
}
}
Usage:
try {
...
} catch (RestClientException restClientException) {
ExceptionUtility.handleException(restClientException);
}

Rolling back transaction with aspect in Spring boot application

I am new to the concept of Aspect-Oriented Programming. I am writing this following aspect using AspectJ in my spring boot application:
#Aspect
public class MyAspect {
private final AspectUtil aspectUtil;
public MyAspect(AspectUtil aspectUtil)) {
this.aspectUtil = aspectUtil;
}
#Pointcut("#within(org.springframework.stereotype.Service)")
public void applicationServicePointcut() {
}
#AfterReturning(value = ("applicationServicePointcut()"))
public void process(JoinPoint joinPoint) {
HttpServletRequest request = aspectUtil.getRequest();
aspectUtil.getHttpVerb(request);
processUtil(request, joinPoint);
}
public void processUtil(HttpServletRequest request) {
...
}
All of the services defined in my application are annotated with #Transactional, one example is given below:
#Service
#Transactional
public class MyService {
..
}
So, here my question is if any exception I throw from my aspect as defined above, then would the associated transaction in the service layer get rolled back?
Actually, my goal is to roll back the entire transaction in case, any exception occurs at this aspect.
An example for a similar requirement 1.4.8. Advising Transactional Operations is available in the documentation.
Exerpt :
The ordering of advice is controlled through the Ordered interface.
.........
The result of the preceding configuration is a fooService bean that
has profiling and transactional aspects applied to it in that order.
If you want the profiling advice to run after the transactional advice
on the way in and before the transactional advice on the way out, you
can swap the value of the profiling aspect bean’s order property so
that it is higher than the transactional advice’s order value...
Please do go through : Advice Ordering to understand the concept better and control the order of advice.
Also go through the conceptual view of calling a method on a transactional proxy:
Basically the idea would be to throw the exception from the custom aspect that should result in the rollback from the Transaction Advisor.
The short answer is it depends. Aspects are ordered in Spring, meaning that they run with a specific order. That means that if your aspect is set to run before the transactional aspect, then no transaction will be created and there would be nothing to actually rollback.
On the other hand, if you set this to run after the transaction aspect and it indeed throws an exception, this would automatically mean that the transaction would have ran and would be committed.
I believe you need to check on ordering of aspects to find the pattern that suits your needs the best.

Handling exceptions during a #Transactional method in Spring

I am trying to figure out how to best handle persistence (and potentially other) exceptions in combination with Spring's #Transactional.
For this post I am just going to take the simple example of a user registration, which can cause DataIntegrityViolationException due to duplicate username.
The following things I have tried and they are not really satisfactory to me:
1. Naive approach: Just catch the Exception
val entity = UserEntity(...)
try {
repo.save(entity)
} catch (e: DataIntegrityViolationException) {
// not included: some checks for which constraint failed
throw DuplicateUsername(username) // to be handled by the controller
}
This does not work when in a #Transactional method, since the persistence exceptions won't happen until the transaction is commited, which happens outside my service method in the spring transaction wrapper.
2. Flush the EntityManager before exiting
Explicitly call flush on the EntityManager at the end of my service methods. This will force the write to the database and as such trigger the exception. However it is potentially inefficient, as I now must take care to not flush multiple times during a request for no reason. I also better not ever forget it or exceptions will disappear into thin air.
3. Make two service classes
Put the #Transactional methods in a separate spring bean and try-catch around them in the main service. This is weird, as I must take care to do one part of my code in place A and the other in place B.
4. Handle DataIntegrityViolationException in the controller
Just... no. The controller has no business (hue hue hue) in handling exceptions from the database.
5. Don't catch DataIntegrityViolationException
I have seen several resources on the web, especially in combination with Hibernate, suggesting that catching this exception is wrong and that one should just check the condition before saving (i.e. check if the username exists with a manual query). This does not work in a concurrent scenario, even with a transaction. Yes, you will get consistency with a transaction, but you'll still get DataIntegrityViolationException when "someone else comes first". Therefor this is not an acceptable solution.
7. Do not use declarative transaction management
Use Spring's TransactionTemplate instead of #Transactional. This is the only somewhat satisfactory solution. However it is quite a bit more "clunky" to use than "just throwing #Transactional on the method" and even the Spring documentation seems to nudge you towards using #Transactional.
I would like some advice about how to best handle this situation. Is there a better alternative to my last proposed solution?
I use the following approach in my project.
Custom annotation.
public #interface InterceptExceptions
{
}
Bean and aspect at spring context.
<beans ...>
<bean id="exceptionInterceptor" class="com.example.ExceptionInterceptor"/>
<aop:config>
<aop:aspect ref="exceptionInterceptor">
<aop:pointcut id="exception" expression="#annotation(com.example.InterceptExceptions)"/>
<aop:around pointcut-ref="exception" method="catchExceptions"/>
</aop:aspect>
</aop:config>
</beans>
import org.aspectj.lang.ProceedingJoinPoint;
public class ExceptionInterceptor
{
public Object catchExceptions(ProceedingJoinPoint joinPoint)
{
try
{
return joinPoint.proceed();
}
catch (MyException e)
{
// ...
}
}
}
And finally, usage.
#Service
#Transactional
public class SomeService
{
// ...
#InterceptExceptions
public SomeResponse doSomething(...)
{
// ...
}
}
Voted to (3),like:
#Service
public class UserExtService extend UserService{
}
#Service
public class UserService {
#Autowired
UserExtService userExtService;
public int saveUser(User user) {
try {
return userExtService.save(user);
} catch (DataIntegrityViolationException e) {
throw DuplicateUsername(username);// GlobalExceptionHandler to response
}
return 0;
}
#Transactional(rollbackFor = Exception.class)
public int save(User user) {
//...
return 0;
}
}
You can use a class annotated with #ControllerAdvice or #RestControllerAdvice to handle the exceptions
When a controller throw a exception you can catch it at this class and change the response status to a suitable one or add an extra info of the exception
This method helps you to maintain a clean code
You have numerous examples:
https://www.javainuse.com/spring/boot-exception-handling
https://dzone.com/articles/best-practice-for-exception-handling-in-spring-boo

#HystrixCommand + Inject Errors with Aspect

We're using Hystrix like so:
#HystrixCommand(...)
public void someOperation() {
...
}
This works great. We'd like to be able to inject errors and sleeps for testing within these methods and we're trying to create an #Aspect for just this purpose:
#Before("execution(* our.package.OurClass.someOperation(..))")
public void causeTrouble() {
...
}
The issue we're seeing is that our advice is running before the Hystrix advice (HystrixCommandAspect) which means that sleeps and exceptions we inject in are treated differently and not handled by Hystrix. Is there a way to ensure our aspect runs inside the Hystrix aspect? I've tried the ordering suggestions in the spring documentation without any luck (see http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj-advice-ordering). Is there another approach to solve this? Thanks.

How to use custom Exception in Session Beans?

EJB 3.1 Session Bean:
import javax.ejb.*;
public class FooException extends EJBException {
}
#Stateless #Local
public class Foo {
public void bar() throws FooException {
if (/* something wrong */) {
throw new FooException();
}
}
}
Now the test:
import org.junit.*;
public class FooTest {
#Test(expected = FooException.class)
public void testException() {
new InitialContext().lookup("Foo").bar();
}
}
The problem is that EJBException is caught in the test, not FooException. Looks like EJB container looses information about my custom exception type and throws a basic type (EJBException). What is wrong here? (it's OpenEJB 3.1)
First of all, you don't need to use the #Local annotation here. This designates an interface as a local interface or when used at a bean (in your case) can be used to point to a local interface (via the value attribute). Neither case is applicable here. Your code as given will also not compile. lookup("Foo") will return an Object that needs to be casted.
Anyway about the problem, the EJB container doesn't loose any information but wraps your exception in an EJBException. This is because FooException ultimately inherits from RuntimeException. Any such exception is treated by the container as a nonapplication exception and for those the EJB spec defines that they should be wrapped.
In your situation you already extend from EJBException, so it seems like this is a corner case. JBoss AS 6 for instance doesn't do the extra wrapping in this situation, but apparently OpenEJB does.
You can solve this problem by either not letting FooException inherit from EJBException, or by catching the exception in your test, unwrapping it and rethrowing the unwrapped exception.
Since your bar method is declaring that it throws FooException, my guess is that you didn't realize that EJBException is a RuntimeException and thus a nonapplication exception. Why did you let FooException inherrit from EJBException? Did you think this was somehow required, or does this need to server some special purpose?
(as an extra hint, make sure you understand the difference between application and nonapplicaton exceptions with respect to rolling back any transaction and destroying the pooled bean)

Categories