Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

JAX-RS 2.0 : Server Side Processing Pipeline

DZone's Guide to

JAX-RS 2.0 : Server Side Processing Pipeline

· Java Zone
Free Resource

Bitbucket is for the code that takes us to Mars, decodes the human genome, or drives your next car. What will your code do? Get started with Bitbucket today, it's free.

The inspiration for this post was the Processing Pipeline section in the JAX-RS 2.0 specification doc (Appendix C). I like it because of the fact that it provides a nice snapshot of all the modules in JAX-RS – in the form of a ready to gulp capsule !

Blog_JAX-RS_Processing_Pipeline

Courtesy – JAX-RS 2.0 Specification Document

So I thought of using this diagram to provide a brief overview of the different JAX-RS components and how they orchestrate with each other.

What’s covered ?

  • Filters (Request and Response)
  • Method matching
  • Injection
  • Interceptors (Request and Response)
  • Entity Providers (Request and Response)

Note: what’s discussed here is the server side processing pipeline i.e. the sequence of actions which are triggered after the client sends an HTTP request (GET, POST, PUT etc)

It all begins when the client (browser or custom REST client) sends an HTTP request to your awesome RESTful service!

Request Filters (chain)

req-filters

The client request is handled by JAX-RS Filters. They are applicable on both the server and client side (we are going to look at server side filters – both request and response based)

  • Filters are optional components and you can write one by simply implementing theContainerRequestFilter interface. They need to be annotated using @Providerannotation for automatic detection by the JAX-RS run time

    @Provider
    
    public class LoggingFilter implements ContainerRequestFilter{
    
    	public void filter(ContainerRequestContext requestContext){
    
    		//logic here - logging etc
    
    	}
    
    }
  • One can mutate the instance of ContainerRequestContext and change attributes like headers, cookies, URI etc. Filters do not allow you to access the HTTP request body/message payload (that’s something which Interceptors can do)
  • Can be used to implement logging, authentication etc
  • If the filter implementation class needs to be executed before the resource method matching, use the @PreMatching annotation on the implementation class.
  • Filters can be bound to ALL JAX-RS methods (globally) or selectively by using@NamedBinding annotation or an implementation of the DynamicFeature interface
  • The @Priority annotation can be used to determine the order of execution of multiple filters – a sequential chain.

Method matching

After (successful) filter execution, the JAX-RS run time initiates the resource method matching process

  • The exact method to be invoked is based on the algorithm outlined by the specification (although JAX-RS providers are not bound by it)
  • It’s determined by a combination of below mentioned annotations
  • @GET, @PUT, @POST, @DELETE etc – these are the annotations which should match up to the actual HTTP operation (the mapping of the annotation to the HTTP verb is rather obvious)
  • @Path – its value (relative to the context root) is used to map the request URI e.g. /tweeters/all
  • @Consumes – its values should match the Content-Type header value sent in the HTTP request
  • @Produces – its values should match the Accept header value sent in the HTTP request

HTTP components injection

After the method matching is complete, the required HTTP components get injected into JAX-RS Resource classes (if configured) by the the JAX-RS run time. All we need to do is use the appropriate annotation

HTTP URI parameters

  • @QueryParam – Extracts the value from the URI query parameter and injects it e.g. a GET request at http://tweeter.com/info?tweeter=abhi_tweeter
  • @PathParam – Extracts the value from the URI template parameter and injects it e.g. a GET request at http://tweeter.com/info/tweeter/abhi_tweeter
  • @MatrixParam – Extracts the value from the URI matrix parameter and injects it

    @Path("info")
    
    @GET
    
    @Produces("application/json")
    
    public Response getTweeterInfo(@QueryParam("tweeter") String tweeterId){
    
    	//fetch details for abhi_tweeter
    
    }
    
     
    
    @Path("info/{tweeter}")
    
    @GET
    
    @Produces("application/json")
    
    public Response getTweeterInfo(@PathParam("tweeter") String tweeterId){
    
    	//fetch details for abhi_tweeter
    
    }
Other HTTP components

JAX-RS makes it easy to access (inject) HTTP request components like headers, cookies and even HTTP form data

  • @HeaderParam – extracts headers of a request. You can also use @Context annotation to inject an instance of HttpHeaders
  • @CookieParam – used to inject HTTP cookies from a HTTP request

    @Path("info/{tweeter}")
    
    @GET
    
    @Produces("application/json")
    
    public Response getTweeterInfo(@HeaderParam("referrer") String refURL, @CookieParam("id") String id){
    
    	//use the injected values of refURL, id from header attribute called header and Cookie named id respectively
    
    }
    
    @Path("info/{tweeter}")
    
    @POST
    
    @Consumes("application/x-www-form-urlencoded")
    
    public Response postInfo(@FormParam("tweeter_id") String id, @FormParam("tweeter_email") String email){
    
    	//use the injected values from HTML form attributes tweeter_id and tweeter_email
    
    }
    
  • @FormParam – can help inject values from attributes sent via a HTML Form using the HTTP POST request

    @Path("info/{tweeter}")
    
    @POST
    
    @Consumes("application/x-www-form-urlencoded")
    
    public Response postInfo(@FormParam("tweeter_id") String id, @FormParam("tweeter_email") String email){
    
    	//use the injected values from HTML form attributes tweeter_id and tweeter_email
    
    }
    
  • @BeanParam – Can help use all the above injection related annotations on the instance variables of a custom domain class rather than using these to inject values into individual method parameters

    public class ClientRequestBean{
    
     @FormParam("tweeter_id")
    
     private String id;
    
     
    
     @FormParam("tweeter_email")
    
     private String email;
    
     
    
     @HeaderParam("referrer")
    
     private String referrer;
    
    // rest of the class
    
    }
    
     
    
    @Path("info/{tweeter}")
    
    @POST
    
    @Consumes("application/x-www-form-urlencoded")
    
    public Response postInfo(@BeanParam ClientRequestBean requestInfo){
    
    	//extract required info from the requestInfo object
    
    } 
    
Request Interceptors (chain)

req-interceptors-entityproviders

Interceptors are applicable on both the server and client side (we are going to look at server side interceptors only – both request and response based)

  • Interceptors help allow mutation of the HTTP request payload before it is processed
  • Request Interceptors are invoked only when a MessageBodyReader (see next topic) implementation is registered with the JAX-RS run time.
  • Interceptors for incoming server requests are handled by implementations of theReaderInterceptor interface and need to be annotated using @Provider annotation for automatic detection by the JAX-RS run time

    @Provider
    
    public CustomReaderInterceptor implements ReaderInterceptor{
    
    	@Override
    
    	public Object aroundReadFrom(ReaderInterceptorContext ric){
    
    		//use the methods from the ReaderInterceptorContext
    
    		ric.proceed();
    
    		//invoke the proceed method to get things moving!
    
    	}
    
    }
  • The ReaderInterceptorContext instance is passed by the JAX-RS run time and it has access to the HTTP body in the form of java.io.InputStream
  • Interceptors can be bound to ALL JAX-RS methods (globally) or selectively by using@NamedBinding annotation or an implementation of the DynamicFeature interface
  • Interceptors can be chained and prioritized (using @Priority) and calling the proceedmethod of the ReaderInterceptorContext automatically invokes the next interceptor in the chain or the MessageBodyReader implementation itself
  • ReaderInterceptor acts as a wrapper around the MessageBodyReader (invokes it internally)

Entity Providers (converting HTTP request payload to Java type)

Entity Providers help in conversion of HTTP message payload to its appropriate Java type (for injection into the method parameters of JAX-RS resource classes) and vice versa

  • The conversion of HTTP request payload to its corresponding Java type is done by a concrete class implementing the MessageBodyReader interface
  • The readFrom method of the MessageBodyReader implementation is where the action takes place. The JAX-RS run time passes in all the contextual information including the payload itself (in the form of an InputStream) which can then be introspected and converted into the appropriate Java type.

    @Path({id}/tweet)
    
    @POST
    
    @Consumes("application/json")
    
    public Response postTweet(Tweet aTweet){
    
    	//Tweet is a custom domain object
    
    }
    
     
    
    @Provider
    
    @Consumes("application/json")
    
    public TweetReader implements MessageBodyReader<Tweet>{
    
    	@Override
    
    	public Tweet readFrom(Class<Tweet> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,String> headers, InputStream payload){
    
    		//use the InputStream (e.g. Tweet in form of JSON payload) and convert it into the domain representation of a Tweet
    
    		//which will then be injected into the postTweet method
    
    		Tweet domainObj = .... ;
    
    		return domainObj;
    
    	}
    
    	@Override
    
    	public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType){
    
    		//use the contextual info - type, genericType and mediaType to determine if this message body reader can actually return the desired Java type
    
    		return true;
    
    	}
    
    }
  • JAX-RS spec mandates that an implementation should contain out-of-of-the-box implementations of MessageBodyReader interface for certain Java types like String, InputStream, File etc

Response Filter (chain)

resp-filters

Response Filters are similar to their Request-centric counterpart discussed previously.

  • Response Filters are optional components and you can write one by simply implementing the ContainerResponseFilter interface.
  • These type of filters are used to modify the response headers, add cookies etc. One can mutate the instance of ContainerResponseContext and change attributes like to achieve this. Filters do not allow you to access the HTTP response body/message payload (that’s something which Interceptors can do)
  • They need to be annotated using @Provider annotation for automatic detection by the JAX-RS run time

    @Provider
    
    public class HeaderModifierFilter implements ContainerResponseFilter{
    
    	public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException{
    
    		//logic here - add custom heasers to the response
    
    	}
    
    }
  • Filters can be bound to ALL JAX-RS methods (globally) or selectively by using@NamedBinding annotation or an implementation of the DynamicFeature interface
  • The @Priority annotation can be used to determine the order of execution of multiple filters – a sequential chain.

Response Interceptors (chain)

resp-interceptors-entityproviders

  • They are invoked only when a MessageBodyWriter (see next topic) is registered to handle outgoing HTTP payload
  • Interceptors for outgoing server responses are handled by implementations of the classWriterInterceptor and need to be annotated using @Provider annotation for automatic detection by the JAX-RS run time

    @Provider
    
    public CustomWriterInterceptor implements WriterInterceptor{
    
    	@Override
    
    	public void aroundWriteFrom(WriterInterceptorContext wic){
    
    		//use the methods from the WriterInterceptorContext
    
    		wic.proceed();
    
    		//invoke the proceed method to get things moving!
    
    	}
    
    }
  • Interceptors can be chained and prioritized (using @Priority) and calling the proceed method of the WriterInterceptorContext automatically invokes the next interceptor in the chain or the MessageBodyWriter implementation itself
  • A WriterInterceptor acts as a wrapper around the MessageBodyWriter (invokes it internally)

Entity Providers (converting Java object to HTTP response payload)

  • The conversion of a Java object returned by the application code to HTTP response payload is done by a concrete class implementing the MessageBodyWriter interface
  • The writeTo method of the MessageBodyWriter implementation is where the action takes place. The JAX-RS run time passes in all the contextual information along with the OutputStream to which the which the response stream can be written to after conversion from its Java type

    @Path({user_id}/tweet/{tweet_id})
    
    @GET
    
    @Produces("application/json")
    
    public Tweet getTweet(@PathParam("user_id") String userid, @PathParam("tweet_id") String tweeter){
    
    	//use the userid and tweetid to fetch the Tweet (domain object) and return it - this will trigger the MessageBodyWriter implementation
    
    }
    
     
    
    @Provider
    
    @Produces("application/json")
    
    public TweetWriter implements MessageBodyWriter<Tweet>{
    
    	@Override
    
    	public void writeTo(Tweet tweet, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,Object> httpHeaders, OutputStream output){
    
    		//extract data from the tweet object and write it to the output stream (e.g. a JSON payload)
    
    	}
    
    	@Override
    
    	public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType){
    
    		//use the contextual info - type, genericType, mediaType and annotations to determine if this message body writer can actually handle the domain object
    
    	}
    
    	@Override
    
    	public long getSize(Tweet tweet, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType){
    
    		//deprecated as of JAX-RS 2.0. Can return -1 by default
    
    		return -1;
    
    	}
    
    }
    
  • JAX-RS spec mandates that an implementation should contain out-of-of-the-box implementations of MessageBodyWriter interface for certain Java types like String, InputStream, File etc

Alright then ! This was a rather brief overview of how server side request processing works in JAX-RS and which components come into play.

Thanks for reading. Cheers !

References

Are you using Bitbucket to accomplish your company's mission? Share your company’s mission with #Forthecode for a chance to be featured on our homepage, our social media channels, or win a free t-shirt!

Topics:

Published at DZone with permission of Abhishek Gupta, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}