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.
About this task
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.
- Create an annotation to indicate that a method is intercepted.
This SecurityChecked annotation indicates a
method where some security information is verified. The following
example illustrates a custom annotation with an intercepted method:
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 {
}
- Create your JAX-RS resource class, and annotate any methods
that you want to intercept with the @com.example.jaxrs.SecurityChecked annotation.
The following example illustrates a JAX-RS resource class with
an intercepted method:
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!";
}
}
- Write an interceptor class that is annotated with the @javax.interceptor.Interceptor annotation
and with the @com.example.jaxrs.SecurityChecked interceptor
marker. Then add a method annotated with the @javax.interceptor.AroundInvoke annotation
with the javax.interceptor.InvocationContext parameter.
You can use the InvocationContext methods to
inspect the method call, as well as determine whether the call should
proceed. The following example illustrates an interceptor:
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;
}
}
- Add a beans.xml deployment descriptor
to your web application (WAR) in the WEB-INF directory.
The existence of the WEB-INF/beans.xml file
indicates that the archive is a JCDI-enabled archive. You are required
to add some information for this instance. The following example illustrates
a WEB-INF/beans.xml file with an interceptor
listed:
<?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.
- Find or create the base type that the decorator must implement.
For instance, the base type might be an interface named Item.
The following example illustrates a common interface used by a decorator:
package com.example.jaxrs;
import javax.ws.rs.GET;
public interface Item {
@GET
public String getInformation();
}
- Create a standard JAX-RS resource class that implements
the base type. The following example illustrates a JAX-RS
resource class that will be decorated:
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 */
}
}
- Create a decorator class. The decorator class
must implement the base type that it wrapa all calls to. The decorator
must be annotated with the @javax.decorator.Decorator annotation.
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;
}
}
- Add a beans.xml deployment descriptor
to your web application (WAR) file in the WEB-INF directory.
The existence of the WEB-INF/beans.xml file
indicates that the archive is a JCDI-enabled archive. You are required
to add information regarding the active decorator classes for this
instance. The following example illustrates a WEB-INF/beans.xml file
with a decorator listed:
<?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>
Results
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.