VRaptor

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.