Search This Blog

Tuesday, November 13, 2018

Example of Aspect Oriented Programming (AOP) using CDI in JavaEE

First create Interceptors

Create Interceptor binding which creates an annotation annotated with @InterceptorBindingthat is used to bind the interceptor code and the target code which needs to be intercepted.

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;

/**
 *
 * @author i88.ca
 */
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface ListSecurity {

}

Now create a class which is annotated with @Interceptor and also annotated with the Interceptor binding we created above. It would contain methods annotated with @AroundInvoke, different lifecycle annotations,@AroundTimeout and others.

import java.io.Serializable;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

/**
 *
 * @author i88.ca
 */
@Interceptor
@ListSecurity
public class ListSecurityInterceptor implements Serializable {

    @AroundInvoke
    public Object enforceSecurity(InvocationContext invocationCtx) throws Exception{
        //do something here before executing the intercepted method
        System.out.println("BEFORE calling method :"+context.getMethod().getName() );
        //now execute the intercepted method and store the return value
        Object returnValue = invocationCtx.proceed();
        //do something more here before return the value
        System.out.println("AFTER calling method :"+context.getMethod().getName() );
        return returnValue;
    }
}

@AroundInvoke designates the method as an interceptor method. An Interceptor class can have only ONE method annotated with this annotation.

You can use the InvocationContext argument of the intercept method for two purposes. You can either extract useful information concerning the EJB method that is being intercepted (for example we used getMethod().getName() API call chain to obtain the name of the intercepted method), or you can continue the execution using proceed() API method. This method will switch the execution flow to the next interceptor in the chain, or to the actual intercepted EJB method, if there are no interceptors left in the chain. This method will return the result of the EJB method call. But we don’t know the returning type, thus proceed() returns an Object instance. If you do know the returning type of the EJB method you can cast the result of proceed() to that particular type, and then use that instance as you wish. Notice that intercept method also returns the result of the actual EJB call. This will be either passed to the next interceptor in the Interceptor chain, or to the client if there is no other interceptors left.
So, any business logic you want to execute before calling the actual EJB method should be placed before calling proceed(). Consequently, you put the code you want to execute after the execution of the actual EJB method, after calling proceed(). Of course you could bypass the normal execution of the EJB method all together if you want.

When ever a target method is intercepted, its context is passed to the interceptor. Using the InvocationContext one can get the method details, the parameters passed to the method.


Last, apply the interceptor to your service class/method:

 @Interceptors(ListSecurityInterceptor.class)
public void MyMethod (or MyClass)