JAVA EE – CDI Interceptor Example

In this post I will explain you one simple way of using interceptors in Java EE.

We have a simple java project that only displays a name wich is setted in the Controller class by the init method. But as you will see next, the final result it’s not the name that is setted by the controler, because we have an interceptor that changes the name behind the scenes.

The index page index.xhtm makes a server request to display the name. But that request is going to be intercepted by our interceptor MyInterceptor.java. Then who makes the request to the controller is the interceptor and if the response is of the type String it changes it to another string. When the page renders it will show not the response from the controller but the object that our interceptor returns to it.

And that’s it. Even without the final user knows nothing about it, the response has been manipulated by our interceptor.

  • Project Scheme
interceptor_project
interceptor_project

 

  • index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        #{controller.name}
    </h:body>
</html>

 

  • Controller.java
package pt.joaobrito.controller;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import pt.joaobrito.annotation.LogToConsoleAndModifyResult;

@Named
@RequestScoped
@LogToConsoleAndModifyResult
public class Controller {

	private String name;

	public Controller() {
	}

	@PostConstruct
	public void init() {
		this.name = "John Doe";
	}

	public String getName() {
		return name;
	}

}

Note that in line 10 we have a special annotation. This marks this bean to be intercepted, as you will see next.  The code in the 20th line, just sets the variable name to John Doe.

  • LogToConsoleAndModifyResult.java
package pt.joaobrito.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;

@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@InterceptorBinding
public @interface LogToConsoleAndModifyResult {

}

This is a simple annotation class (out of the scope of this post, for now). The important thing here is the @InterceptorBinding annotation.

  • MyInterceptor.java
package pt.joaobrito.interceptor;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import pt.joaobrito.annotation.LogToConsoleAndModifyResult;

@Interceptor
@LogToConsoleAndModifyResult
public class MyInterceptor {

	@AroundInvoke
	public Object interceptAndLog(InvocationContext ic) throws Exception {
		Logger logger = getLogger(ic);
		// this is executed before the method being intercepted
		logger.log(Level.INFO, "before the method being intercepted...");

		// the object returned after the execution of the intercepted method
		Object result = ic.proceed();

		// if the intercepted method returns a String, we can modify it
		if (result instanceof String) {
			// this is executed real result of the intercepted method
			logger.log(Level.INFO, "the real result of the intercepted method is: " + (String) result);

			// now we change the result without the final user knows that the method is being intercepted
			result = "Jane Doe";
		}

		try {
			// we return the modified object, or the original (if it was not a string)
			return result;
		} finally {
			// this is executed after the method being intercepted
			logger.log(Level.INFO, "after the method being intercepted... thne name is: " + (String) result);
		}
	}

	private Logger getLogger(InvocationContext ctx) {
		return Logger.getLogger(ctx.getMethod().getClass().toString());
	}
}

In the MyInterceptor class we have 3 important annotations:

@Interceptor  (line 10),
@LogToConsoleAndModifyResult  (line 11) and the
@AroundInvoke  (line 14).

The first one makes this bean an interceptor. The second, marks this interceptor to intercept all methods in classes  annotated with the the same annotation. The last one, marks the method that is going to manipulate all the data.

Note that this method must returns an Object and as a parameter it takes the invocation context.

First we have a logger that prints out to the console a message before the interception. Then with the help of the invocation context, it lets the original method to proceed and keeps the result. Then it prints again to the console the real name returned by the controller (John Doe). After this, it changes the return value to Jane Doe, that is exactly what is going to be displayed in the page as the final result.

  • beans.xml
<beans>
	<interceptors>
		<class>pt.joaobrito.interceptor.MyInterceptor</class>
	</interceptors>
</beans>

Finally, in order to use interceptors we must register them in the beans.xml file (line 3). Another possibility is to annotate the controller with @Interceptors({MyInterceptor.class}) but this approach is not recommended.

  •  The Log

the log messages

Here are the three messages sent to the console.

  • The result page

web page

As you can see here the displayed name isn’t John Doe, as you might expect, but the modified result: Jane Doe.

—
Source code

Feel free to comment.

Leave a Reply

Your email address will not be published. Required fields are marked *