How to catch the exception thrown from a Spring AOP Advice - java

I have my own exception "MyOwnException" and throw this exception from my service class
public void service() throws MyOwnException
{
// some code
}
Now I want to catch MyOwnException in an advice and rethrow a brand-new Exception
public class SimpleThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target,
MyOwnException ex) throws Throwable {
throw new Exception("new Description",ex);
}
}
Now, how can I catch the re-thrown Exception from the above Advice SimpleThrowsAdvice?

You should use the Around advice to do that. See here Spring AOP AfterThrowing vs. Around Advice

Related

Use an aspect written for spring application in guice application

I had written an aspect as part of an application using Spring AOP/AspectJ annotations similar to below aspect:
#Aspect
#Component
public class LoggingAspect {
#Around("#annotation(loggable)")
public Object log(final ProceedingJoinPoint joinPoint, final Loggable loggable) throws Throwable {
//log method arguments
try {
Object returnValue = joinPoint.proceed();
// log return value
return returnValue;
} catch (Exception ex) {
// publish exception metrics to some other system
throw ex;
}
}
}
Now I want to use this same aspect in another project, but this project uses Guice instead of Spring.
I was reading about Guice AOP which requires aspect to implement the MethodInterceptor interface and thus I will need to implement the below method:
Object invoke(MethodInvocation methodInvocation) throws Throwable;
What I was thinking was to modify the already existent aspect to implement the MethodInterceptor and internally call the log method. Something like below:
#Aspect
#Component
public class LoggingAspect implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
// call already defined log method, but that method expects a ProceedingJoinPoint, however
// I get MethodInvocation as input parameter in this method
}
// already defined log method
#Around("#annotation(loggable)")
public Object log(final ProceedingJoinPoint joinPoint, final Loggable loggable) throws Throwable {
......
.....
}
But due to incompatible type between two methods, I am unable to proceed.
Is there a way I can reuse the existing code instead of writing a brand new aspect with duplicate code to support Guice?
If I understand correctly, you want to reverse the control flow, which can be done with callbacks.
#Aspect
#Component
class LoggingAspect implements MethodInterceptor {
#Around("#annotation(loggable)")
public Object log(final ProceedingJoinPoint joinPoint, final Loggable loggable) throws Throwable {
return log(joinPoint::getArgs, () -> joinPoint.proceed(joinPoint.getArgs()));
}
#Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
return log(methodInvocation::getArguments, methodInvocation::proceed);
}
public Object log(Supplier<Object[]> arguments, Supplier<Object[]> proceed) {
Object[] args = arguments.get();
//log method arguments
try {
Object returnValue = proceed.get();
// log return value
return returnValue;
} catch (Exception ex) {
// publish exception metrics to some other system
throw ex;
}
}
}
BTW do you intentionally catch only Exception and not Throwable? Errors would not be logged.

#Async will not call by #ControllerAdvice for global exception

I have a service class with #Async method and If it's calling method throwing any exception then the #ControllerAdvice will not call for global exception handling. But for other classes and services it will call advice and sending email properly.
#Service
public class FileScanServiceImpl implements FileScanService {
#Override
#Async
public void scanFileScheduler() throws MQException {
try{
messageProducer.putFileNameToMQ(fileName);
} catch (Exception e) {
ExceptionUtility.handleException(e, currentFile);
}
}
The ExceptionUtility is used for checking instance on exception and doing some functionality there and throwing custom exception.
public static void handleException(Exception e throws MQException {
String errMsg = "";
if (e instanceof MQException) {
// some functionality
throw new MQException(subject, errMsg);
}
}
And this is my #ControlleAdvice
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(MQException.class)
#ResponseBody
public void handleMQException(HttpServletRequest request, MQException ex) {
// send email
}
}
It there any solution for #Async which will call #ControllerAdvice for global exception, also the existing functionality will not break.
#ExceptionHandler was created to catch only "synchronous exceptions". If it had the ability to catch exceptions from asynchronous threads, then when several threads start and if any of them fail, the request to the server would be interrupted completely and the system could remain in an inconsistent state (due to many other active threads generated by this request)
For handling asynchronous exceptions Spring has the AsyncUncaughtExceptionHandler interface:
public class YourAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
#Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
// Your exception handling logic
}
}
More information can be found here in the Exceptions section: https://www.baeldung.com/spring-async

Exception Handling in JAX-RS

java 8, spring, rest
I am trying to capture the Response that comes from exception mapper, and do something with it in the caller which throws the exception. Thanks.
#Provider
public class CustomerExceptionHandler implements ExceptionMapper<CustomerException>
{
#Override
public Response toResponse(CustomerException exception)
{
return Response.status(Status.BAD_REQUEST).entity(CustomerException.getMessage()).build();
}
}
public class CustomerException extends Exception implements Serializable
{
private static final long serialVersionUID = 1L;
public CustomerException() {
super();
}
public CustomerException(String msg) {
super(msg);
}
public CustomerException(String msg, Exception e) {
super(msg, e);
}
}
public class ExceptionDemo{
public void getExceptionResponse(){
//do something
throw new CustomerException("Something is wrong");// CustomerExceptionHandler is going to return me a Response, how can I capture the response here?
//capture response and do something with it
}
}
I'm not sure ExceptionMappers work in the way you think they do.
When some code in the endpoint throws an exception, and this exception percolates all the way out of the endpoint and back into the container itself (Spring in this case), then the registered ExceptionMappers are consulted to see if they match the thrown exception, and the relevant one's public Response toResponse(T e) {} method is called to transform it into a Response.
The ExceptionMapper doen't get called as part of your endpoint code, and you won't be able to take action based on its resultant Response because it hasn't yet been called. You just need to throw the exception out of the endpoint.

Handling Exception in Spring boot Application with Hibernate

I am building a REST API with Spring boot and DAO layer is implemented in Hibernate.I need to understand the correct way of throwing and handling Exception in the Application.Currently I am doing it in this way
#Repository
public class UserDaoImpl
{
public getAllUsers() throws Exception
{
//get All Users from DB
}
}
#Service
public class UserServiceImpl
{
public getAllUsers throws MyCustomException
{ try{
userDaoImpl.getAllUsers();
}
catch(Exception e)
{
throw MyCustomException();
}
}
}
and In Exception Mapper
#ControllerAdvice
public class ApplicationExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({MyCustomException.class})
#ResponseBody
public ResponseEntity<?> handleCustomException(Exception e) {
log.error("", e);
Map<String, String> error = new HashMap<String, String>();
error.put("message", e.getMessage());
return new ResponseEntity<>(error, HttpStatus.NOT_ACCEPTABLE, MessageResource.getLogMessage("BAD_REQUEST_EXCEPTION"));
}
}
public class MyCustomException extends RuntimeException
{
///// ....
}
So I have added throws clause (throws Exception) in DAO layer and catch at service layer and wrap it in Custom Exception(unchecked exception) and do not propogate the exception at controller layer.
Is this correct ? or there is some better way?
I'd recommend you to have general #ExceptionHandler({Exception.class}) for all cases that you don't want to handle specifically.
Also it's okay to create separate exception classes for situations that require custom handling.
It depends on what do you want to achieve.
About your case. Exception in DAO layer does not necessary mean that request was wrong or did not provide correct parameters. It could be mapping problems, DB access problems and etc. So I would not wrap it to my custom exception, or at lest wrap in to general DataAccessException, make good logging around that and return some general error code to the client.

Custom Exception is not handled with #ExceptionHandler annotated method

I have a custom exception class defined as
public class CustomAuthenticationException extends RuntimeException{
}
From a controller method I am throwing this exception as below
#RequestMapping(value="/tasks", method=RequestMethod.GET)
public String loadTasks(HttpServletRequest request){
try
{
if (!isAuthenticatedRequest(request))
{
throw new CustomAuthenticationException();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
return "tasks/tasks";
}
To catch this exception from that controller's scope, I have defined a method with #ExceptionHandler annotation as below
#ExceptionHandler(CustomAuthenticationException.class)
public void handleCustomException(CustomAuthenticationException ex){
//method is not getting invoked
}
When I initiate the GET request and expect the exception to be handled by the aformentioned method, I get only the error stack trace in the console. The exception handler method is never invoked.
But, with other defined exceptions like MethodArgumentNotValidException, the handler methods are invoked correctly. For example I got the following exception handler working:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseBody
public ErrorResponseHolder handleFieldValidationError(MethodArgumentNotValidException ex, HttpServletResponse response){
//method got invoked. do something with the exception
}
How can I resolve the issue with the custom exceptions ?
Handling of the exception is not proper, in a method loadTasks you are throwing the exception and catching the exception hence it is not propagating.
If you wanted to handle unhanded exceptions, for example generic exceptions (Exception.class) you need to write a method that should handle all these exception in common exception handling class.
#ExceptionHandler(Exception.class)
public void handleUnhandledException(Exception ex){
// handle the exception here
}
Once you are throwing the exception never ever catch the exception in same method, catch the exception where you are sending the proper response.

Categories