Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC: bind an exception handler to particular method

Good day!

I have a @Controller. Some of its methods throw the same exception, but I want to handle this exceptions in different way.

Is there a way how to bind an @ExceptionHandler to a particular method?

like image 365
V. Artyukhov Avatar asked Jul 08 '13 09:07

V. Artyukhov


1 Answers

You need to use AOP tools like CDI Interceptor or AspectJ to achieve this cross-cutting concerns. A Concern is a term that refers to a part of the system divided on the basis of the functionality.

Basically this type of feature is used to handle logging, security and also handling the errors... which are not part of your business logic...

Like if you want to change the logger for application from log4j to sl4j then you need to go through each and every classes where you have used log4j and change it. But if you have used AOP tools then you only need to go the interceptor class and change the implementation. Something like plug and play and very powerful tool.

Here is a code snippet using JavaEE CDI Interceptor

/*
    Creating the interceptor binding
*/
@InterceptorBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface BindException {

}

After we have define interceptor binding we need to define interceptor binding implementation

/*
    Creating the interceptor implementation
*/
@Interceptor
@BindException
public class ExceptionCDIInterceptor {

    @AroundInvoke
    public Object methodInterceptor(InvocationContext ctx) throws Exception {
        System.out.println("Invoked method " + ctx.getMethod().getName());
        try {
            return ctx.proceed(); // this line will try to execute your method
                                 // and if the method throw the exception it will be caught  
        } catch (Exception ex) {
            // here you can check for your expected exception 
            // code for Exception handler
        }
    }

}

Now we only need to apply interceptor to our method

/*
    Some Service class where you want to implement the interceptor
*/
@ApplicationScoped
public class Service {

    // adding annotation to thisMethodIsBound method to intercept
    @BindException
    public String thisMethodIsBound(String uid) {
        // codes....

        // if this block throw some exception then it will be handled by try catch block
        // from ExceptionCDIInterceptor
    }
}

You can achieve same feature using AspectJ also.

/*
    Creating the Aspect implementation
*/
@Aspect
public class  ExceptionAspectInterceptor {

    @Around("execution(* com.package.name.SomeService.thisMethodIsBound.*(..))")
    public Object methodInterceptor(ProceedingJoinPoint ctx) throws Throwable {
        System.out.println("Invoked method " + ctx.getSignature().getName());
        try {
            return ctx.proceed(); // this line will try to execute your method
                                 // and if the method throw the exception it will be caught  
        } catch (Exception ex) {
            // here you can check for your expected exception 
            // codes for Exception handler
        }
    }
}

Now we only need to enable the AspectJ to our application config

/*
    Enable the AspectJ in your application
*/
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

    @Bean
    public SomeService SomeService() {
        return new SomeService();
    }

}

/*
    Some Service class where you want to implement the Aspect
*/
package com.package.name;
public class SomeService {

    public String thisMethodIsBound(String uid) {
        // codes....

        // if this block throw some exception then it will be handled by try catch block
        // from ExceptionAspectInterceptor
    }
}

I have code example in my git repo https://github.com/prameshbhattarai/javaee-exceptionBinding by using CDI interceptor.

like image 112
pramesh Avatar answered Oct 19 '22 00:10

pramesh