28 March 2013

JAX-RS 2.0 preview (updated)

Here's an overview of the most important new features in JAX-RS 2.0 (JSR339).
The JSR is currently in public review, so this is subject to change.

  • Asynchronous REST web services
  • REST web services are based on servlets. So the new asynchronous REST support looks a lot like the new asynchronous servlet support.
    The response to an asynchronous web service can be delegated to another thread.
     The webservice needs to pass the asynchronous response, to allow it to send a response.

    @Path ("/rest2/async")
    public class NoWaiter{
      @Asynchronous
      @GET 
      public String delegate(@Suspended AsyncResponse ctx) {
        // put context on a queue
        // for job to be picked up by a thread
        bloq.add(ctx);
        // exit immediatly
      }
    }
    
    class Handler implements Runnable{
      public void run(){
        AsyncResponse ctx bloq.take();
        // return response
        ctx.resume("response");
      }
    } 
  • Client API
  • Similar to Jersey 1 client API (some names change)
    Client client = ClientFactory.newClient();
    String result = client.target(“http://reasonsto.be”)
      .request("text/plain")
      .get(String.class); 
    
    Chaining async() in the call, the client becomes asynchronous:
    Future<String> result = client.target(“http://reasonsto.be”)
      .request("text/plain")
      .async()
      .get(String.class);
    You can also pass a listener to the asynchronous client:
    Future<String> result = client.target(“http://reasonsto.be”)
      .request("text/plain")
      .async()
      .get(new Hark()); 
    
    class Hark implements InvocationCallback<String>
    {
    public void completed(String result) {…}
    public void failed(InvocationException err) {…}
    }
  • Filters and Entity Interceptors
    • Similar to Jersey 1 filters 
    • @Provider annotated 
    • set order using @Priority
    • Filters wrap around an entire HTTP request. Mostly deal with HTTP headers, URI, method...
      • interface ContainerResponsFilter (javax.ws.rs.container)
        • void filter(ContainerResponseContext ctx) throws IOException
      • interface ContainerRequestFilter
        • void filter(ContainerRequestContext ctx) throws IOException 
        • Can have an additional @PreMatching annotation to run before JAX-RS resource method is selected (default is after resource method selection)
      • Throwing an exception will veto further processing of the message
      • javax.ws.rs.client contains similar clientside filters. Just replace Container with Client in the above interfaces. 
        • not annotated, but ClientBuilder, Client, and WebTarget all implement the Configurable interface. You can add your filter using its register(yourFilter) method.
    • Entity Interceptors wrap around the HTTP body <=> java Object marshalling/unmarshalling (e.g. for supporting compression encoding)
      •  interface WriterInterceptor
        • void aroundWriteTo(WriterInterceptorContext ctx) throws IOException, WebApplicationException
      • interface ReaderInterceptor
        • Object aroundReadFrom(ReaderInterceptorContext ctx) throws IOException, WebApplicationException
      • The aroundXXX  method naming indicate that these work like servlet filters:
        1. do some stuff
        2. ctx.proceed(): delegate to the next interceptor in the chain (of there is one)
        3. do some more stuff
    • Binding
      • Global
        •  @Provider
      • Local 
        • Using DynamicFeature
        • Using @NameBinding
          • Indicate that the usage of this resourcemethod is to be logged, using our own annotation:
          • @LogMe
            @GET
            @Produces("text/html")
            public String getXml(){ 
              return "<html>...</html>"
            }
            
          • Define the annotation
          • @NameBinding
            public @interface Logme{}
            
          • Implement the annotation
          • @LogMe
            public class LoggerLoggingFilter 
              implements ContainerRequestFilter, ContainerResponseFilter {
            // your logging code 
            }
            
        • Dynamic
          1. The filter is bound using one of the above methods, but there is an extra check to see if the filter should be applied
          2. The filter must implement the DynamicBinding interface
          3. The filter is applied only if the isBound() method returns true 
    • JSR303 validation
    • @Produces allows server to specify a mime type preference, using the qs attribute
    • Form class can be used as a resource method argument to capture a map of query parameters (shorthand for UriInfo.getQueryParameters()).