You can use Java Contexts and Dependency Injection (JCDI) to write interceptors and decorators for Java API for RESTful Web Services (JAX-RS) resource types. For example, you can use the interceptor and decorator capabilities from JCDI to log calls to a particular class or to complete a security check before invoking a method when using JCDI-enabled web applications with JAX-RS.
Two methods exist for adding cross-cutting concerns to your application. Interceptor bindings need a custom annotation. The annotation is used to mark which methods should be intercepted. Decorators implement the base type. Then, using an @javax.decorator.Decorator injected instance, you can implement your special logic around calls to the injected delegate.
package com.example.jaxrs;
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
@InterceptorBinding
@Target( {ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityChecked {
}
package com.example.jaxrs;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
@Path("exampleInterceptor")
@RequestScoped
public class MyResourceBean {
@GET
@com.example.jaxrs.SecurityChecked
public String echo(String hello) {
return "Hello world!";
}
}
package com.example.jaxrs;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
@Interceptor
@com.example.jaxrs.SecurityChecked
public class SecurityCheckInterceptor {
@AroundInvoke
public Object checkSecurity(InvocationContext context) throws Exception {
/* check the parameters or do a generic security check before invoking the
original method */
Object[] params = context.getParameters();
/* if security validation fails, you can throw an exception */
/* invoke the proceed() method to call the original method */
Object ret = context.proceed();
/* perform any post method call work */
return ret;
}
}
<?xml version="1.0 encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance" xsi:schemeLocation="http://java.sun.com/xml/ns/javaee http://
java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>com.example.jaxrs.SecurityCheckInterceptor</class>
</interceptors>
</beans>
In the previous steps, you configured a
web application to use JCDI, added a custom annotation to mark methods
for interception, and wrote an interceptor. When a marked method is
called, the interceptor is used to determine whether the marked method
should be called and can perform additional logic. You must list the
interceptors in your beans.xml deployment descriptor.In the remaining steps, you create and enable a decorator in a JCDI-enabled web application. Interceptor bindings require an annotation to mark methods for interception. Decorators implement the common base type and can wrap the calls.
package com.example.jaxrs;
import javax.ws.rs.GET;
public interface Item {
@GET
public String getInformation();
}
package com.example.jaxrs;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.Path;
@Path("decoratedresource")
@RequestScoped
public class MyItem implements Item {
public String getInformation() {
/* return some information */
}
}
The decorator must have a special field, called a delegate injection point, with the base type. The field can have any variable name, and should have an @javax.inject.Inject and an @javax.decorator.Delegate annotation. This field will be the original object that is being decorated. You can then use this decorated object in your implementation calls.
The following example illustrates a basic decorator class:
package com.example.jaxrs;
import javax.decorator.Decorator;
import javax.decorator.Delegate;
import javax.inject.Inject;
@Decorator
public class MyItemDecorator implements Item {
@Inject
@Delegate
private Item decoratedItem;
public String getInformation() {
/* perform some logging */
String info = decoratedItem.getInformation();
/* perform some more logging */
return info;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance" xsi:schemeLocation="http://java.sun.com/xml/ns/javaee http://
java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>com.example.jaxrs.SecurityCheckInterceptor</class>
</interceptors>
<decorators>
<class>com.example.jaxrs.MyItemDecorator</class>
</decorators>
</beans>
You have configured a web application to use JCDI, created a method interceptor for one resource, created a decorator, and enabled it to decorate your method calls for a second resource.