Network Deployment (Distributed operating systems), v8.0 > End-to-end paths > Web services - RESTful services > Use Java contexts and dependency injection with JAX-RS > 4. Implementing JAX-RS resources with JCDI functionality.
Implement a JAX-RS resource with decorators and method interceptors
We 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 the 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.
Procedure
- 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 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. We 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. We 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.
Implement JAX-RS resources with different lifecycle scopes
Implement JAX-RS resources with dependency injection
Use Java contexts and dependency injection with JAX-RS
Related
Web services specifications and APIs