When intercept?
Interceptors are used to perform some task before or after a business logic like data validation, connection control, database transaction, logs and data encryption/compression.
How to intercept?
VRaptor uses an approach where the interceptor defines who will be intercepted, more closer to the interception approaches used by AOP (Aspect Oriented Programming).
Therefore, to intercept a request, you need just to annotate the class with the @Intercepts
. Like any other component, you can use scoped annotation to define the interceptor life cicle. The default scope for an interceptor is RequestScoped
.
A simple example
The class below shows an example how to intercept all requests in a request scoped and simply show the console output that is being invoked. Remember that the interceptor is a component like any other and can receive any dependencies using Dependency Injection.
@Intercepts
@RequestScoped
public class Log {
@Inject
private HttpServletRequest request;
@AroundCall
public void intercept(SimpleInterceptorStack stack) {
System.out.println("Intercepting " + request.getRequestURI());
// code to be executed before the stack
stack.next(); // execute the stack
}
}
To execute the code just before or after the controller execution, we can use annotations @BeforeCall
and @AfterCall
:
@Intercepts
@RequestScoped
public class Log {
@BeforeCall
public void before() {
// code executed before
}
@AfterCall
public void after() {
// code executed after
}
}
Defining when intercepting
In the example above, all requests are intercepted. But we can define, as example, only methods annotated with @Audit
annotation. You just to implement a method that returns a boolean
with the necessary condition and annotate it with @Accepts
.
@Accepts
public boolean accepts(ControllerMethod method) {
return method.containsAnnotation(Audit.class);
}
Or we can use the more simple way. The example above is a very common case and thus often repeat this code. For this situation we can use the annotation @AcceptsWithAnnotations
as described below:
@AcceptsWithAnnotations(Audit.class)
public class AuditInterceptor {
@AroundCall
public void around(SimpleInterceptorStack stack) {
stack.next();
}
}
Customizing your Accepts
In the example above we used a customized accepts with annotation AcceptsWithAnnotations
. And if you need, you can create your custom annotation to define when intercepts. Before you need to create your annotation like this example below.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@AcceptsConstraint(WithAnnotationAcceptor.class)
@Inherited
public @interface AcceptsWithAnnotations {
public Class<? extends Annotation>[] value();
}
As you can see, we use the Annotation @AcceptsConstraint
to define the class that have our logic. Now we need to implement this class.
public class WithAnnotationAcceptor implements AcceptsValidator<AcceptsWithAnnotations> {
@Override
public boolean validate(ControllerMethod controllerMethod, ControllerInstance instance) {
//your code here
return true;
}
@Override
public void initialize(AcceptsWithAnnotations annotation) {
//your code here
this.allowedTypes = Arrays.asList(annotation.value());
}
}
This class needs only to implements AcceptsValidator<T>
interface, where generic T
is the type of your custom annotation.
How to guarantee the order: after and before
If you need to guarantee the execution order for your interceptors, you can use the after
and before
attributes from the @Intercepts
annotation. Like the example below, if you have an interceptor named FirstInterceptor
that needs to be executed before SecondInterceptor
, you can declare like this:
@Intercepts(before=SecondInterceptor.class)
public class FirstInterceptor {
...
}
and:
@Intercepts(after=FirstInterceptor.class)
public class SecondInterceptor {
...
}
You can define one more Interceptor:
@Intercepts(after={FirstInterceptor.class, SecondInterceptor.class},
before={FourthInterceptor.class, FifthInterceptor.class})
public class ThirdInterceptor {
...
}
Note: VRaptor throws an exception if there is a cycle in the interceptors order. So be careful when you define interceptors order to avoid cicles.