X

JAX-RS 2.0 Early Draft Explained - Java EE 7 Making Progress

Guest Author


href="http://jcp.org/aboutJava/communityprocess/edr/jsr339/index.html">JAX-RS
2.0 Early Draft has been available for about 3 months now.
JAX-RS 2.0, just like JPA 2.1, was one href="http://blogs.oracle.com/arungupta/entry/jax_rs_2_0_and">one
of the first JSRs to be filed as part of href="http://blogs.oracle.com/arungupta/entry/java_ee_7_key_features">Java
EE 7. Several other specifications in Java EE 7 have released
early drafts as well (href="http://jcp.org/aboutJava/communityprocess/edr/jsr344/">JavaServer
Faces 2.2, href="http://jcp.org/aboutJava/communityprocess/edr/jsr346/index.html">CDI
1.1, href="http://jcp.org/aboutJava/communityprocess/edr/jsr345/index.html">EJB
3.2, and more coming as well) and I'll cover them in later
blogs.



Here are the topics covered so far:
  • href="http://blogs.oracle.com/arungupta/entry/jpa_2_1_early_draft">JPA
    2.1 Early Draft Explained
  • What's new in JSF
    2.2?
    (external contribution)


JAX-RS 2.0 is a brand new specification and here are the main
highlights so far:
  • Client API: The HTTPUrlConnection
    is too low level and is not RESTful-oriented. Invoking a RESTful
    resource using this class would look like:



    URL url = new URL("http://.../atm/balance");

    HttpURLConnection conn = (HttpURLConnection)
    url.openConnection();

    conn.setRequestMethod("GET");

    conn.setDoInput(true);

    conn.setDoOutput(false);

               


    BufferedReader br = new BufferedReader(new
    InputStreamReader(conn.getInputStream()));

    String line;

    while ((line = br.readLine()) != null) {

        out.println(line);

    }




    Notice, how much code has to be written and its brittle. Some
    JAX-RS 1.0/1.1 implementations already provide a higher-level
    client-side API to access the Web resources. For example, read
    href="http://blogs.oracle.com/arungupta/entry/totd_57_jersey_client_api">
    TOTD #57 for more details about Jersey Client API. A
    slightly more advanced sample to access Twitter timeline using
    Jersey Client API is described in href="http://blogs.oracle.com/arungupta/entry/totd_143_retrieve_twitter_user">TOTD
    #143.



    JAX-RS 2.0 introduces a standard Client API to in javax.ws.rs.client
    package to access the Web resource. It also share features with
    JAX-RS server API (readers/writers).



    A simple usage looks like:



    Client client = ClientFactory.newClient();

    String balance = client.target("http://.../atm/balance")

                          
    .request("text/plain")

                          
    .get(String.class);




    Instead of Client client = ClientFactory.newClient(),
    would you like @Inject Client client then vote for
    JAX_RS_SPEC-170.



    Path and query parameters can be easily specified using the
    builder pattern as shown below:



    Client client = ClientFactory.newClient();

    String balance =
    client.target("http://.../atm/{card}/balance")

                          
    .pathParam("card", "1111222233334444")

                          
    .queryParam("pin", "1234")

                          
    .request("text/plain")

                          
    .get(String.class);




    See how the template in the target path is automatically
    substituted with the correct value. The request type is
    specified to be "text/plain" and GET method of this web resource
    is invoked. This will be translated to:



    http://.../atm/1111222233334444/balance?pin=1234



    A POST request will look like:



    Money balance =
    client.target("http://.../atm/{card}/withdraw")

                         
    .pathParam("card", "1111222233334444")

                         
    .queryParam("pin", "1234")

     
                       
    .request("application/json")

                         
    .post(text("50.0"), Money.class);



    There is also generic command pattern that enables separation of
    concern between the creator and submitteruseful for batch
    processing using Invocation. And the code would
    look like:



    Invocation inv1 =
    client.target("http://.../atm/{card}/balance")

                
              
    .pathParam("card", "1111222233334444")

                 
             
    .queryParam("pin", "1234")

                
              
    .request("text/plain")

                 
              .buildGet();




    Invocation inv2 =
    client.target("http://.../atm/{card}/withdraw")

                    
           .pathParam("card",
    "1111222233334444")

                     
          .queryParam("pin", "1234")

                    
           .request("application/json")

                     
          .buildPost(text("50.0"));



    And once the Invocations are ready then they can
    be invoked.



  • Filters and Handlers:
    The filters and handlers allow app developers to perform message
    request pre-processing and response post-processing via
    well-defined extension points on the client- and server-side.
    This is yet another feature that was supported by several JAX-RS
    1.0/1.1 implementations with each using slightly different
    semantics and now getting standardized in JAX-RS 2.0.



    Filters are non-wrapping extension points, allow pre-processing
    without modifying the request itself. A filter implements
    interface RequestFilter or ResponseFilter
    or both and is annotated with @Provider. A logging
    filter that simply logs the message may look like:



    @Provider

    class LoggingFilter implements RequestFilter, ResponseFilter {



        @Override

        public FilterAction preFilter(FilterContext
    ctx) throws IOException {

           
    logRequest(ctx.getRequest());

            return
    FilterAction.NEXT;

        }



        @Override

        public FilterAction
    postFilter(FilterContext ctx) throws IOException {

           
    logResponse(ctx.getResponse());

            return
    FilterAction.NEXT;

        }

    }



    Multiple filters are grouped in filter chains. The response from preFilter
    and postFilter indicate whether the next filter in
    the chain need to be executed (FilterAction.NEXT)
    or stopped (FilterAction.STOP).



    Handlers provide wrapping extension points. A handler implements
    interface ReadFromHandler or WriteToHandler
    or both and is annotated with @Provider. A GZIP
    filter that provides deflate and inflate capabilities may look
    like:



    @Provider

    class GzipHandler implements ReadFromHandler, WriteToHandler {

        @Override

        public Object
    readFrom(ReadFromHandlerContext ctx) throws IOException {

            InputStream old =
    ctx.getInputStream();

           
    ctx.setInputStream(new GZIPInputStream(old));

            try {

               
    return ctx.proceed();

            } finally {

               
    ctx.setInputStream(old);

            }

        }



        @Override

        public Object writeTo(WriteToHandlerContext
    ctx) throws IOException {

           
    OutputStream old = ctx.getOutputStream();

            GZIPOutputStream
    gzipOutputStream =
    new GZIPOutputStream(old);

           
    ctx.setInputStream(gzipOutputStream);

            try {

               
    return ctx.proceed();

            } finally {

               
    gzipOutputStream.finish();

               
    ctx.setOutputStream(old);

            }

        }

    }



    Multiple handlers are grouped in handler chains. The proceed
    method must be explicitly called in order for the next handler
    in the chain to be invoked.



    In the direction of flow
    the filters always executed before handlers. The following
    diagram shows the exact execution order on client and
    server-side:



    src="//cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/f4a5b21d-66fa-4885-92bf-c4e81c06d916/Image/b10408fd130d04d53217ed267f8644b2/jaxrs2_filters_handler_execution_order.png">



    The handlers and filters can be associated to each method of a
    resource specifically using @NameBinding. The
    specification defines @GlobalBinding to associate
    handlers and filters to all methods of a resource but the recent
    version of the specification removes it and makes it a default.
    Also look at href="http://java.net/jira/browse/JAX_RS_SPEC-146">JAX_RS_SPEC-146
    that asks for a mechanism to override the global
    filters/handlers.



    The dynamic binding, enabled by implementing DynamicBinding,
    provide more control on the association with resources and
    methods.

  • Hypermedia: Linking
    resources together is one of the main RESTful principles. There
    are structural links
    that are used to avoid sending a complete representation of a
    resource and enable lazy loading. The clients can follow these
    type of links to retrieve the "pieces" they need. A style="font-style: italic;">transitional link is used
    to update the state of a resource and is typically identified by
    a "rel" attribute. Structural links are normally in the entity;
    transitional links could be in link headers or the entity.



    JAX-RS 2.0 will only support transitional links in headers using
    newly added Link and LinkBuilder
    classes. The proposed Client API can also create a
    target from a link. The code may look like:



    Response r =
    client.target("/product").request("application/json").get();

    ResponseHeaders rh = r.getHeaders();

    if (rh.hasLink("ship")) {

       
    client.invocation(rh.getLink("ship")).invoke();

    }




    On the server side, ResponseBuilder has support
    for adding one or more link headers. The code may look like:



    @Path("/products")

    public class MyResponse {



        @GET

        @Path("{id}")

        @Produces({"application/json",
    "application/xml"})

        public Response
    getProduct(@PathParam("id")int id) {

            Product product =
    new Product(id);

            return Response

                   
    .ok(product)

                   
    .link("http://.../orders/" + id + "/ship", "ship")

                   
    .build();

        }

    }




  • Validation: Web
    resources must validate data received in query or header
    parameters or entity bodies. Currently this validation has to be
    performed in the application code. The Bean Validation
    specification already defines a extensible mechanism to specify
    validation constraints on a bean. So the JAX-RS specification
    leverages that and introduces support for declarative
    validation. The constraint annotations can be specified in
    public constructor parameters, method parameters, fields and
    bean properties. In addition, they can also decorate resource
    classes, entity parameters and resource methods. Here is a
    sample class augmented with constraint annotations:



    @Path("/")

    class ProductResource {



        @POST

       
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)

        public void addProduct(@NotNull
    @FormParam("productName") String name,

                              
    @NotNull @Category @FormParam("category") String category) {

            . . .

        }

    }




    The @NotNull is a pre-defined constraint in the
    Bean Validation API and ensures that the target parameters are
    not null. The @Category is a user-defined
    constraint using the extensible mechanism provided by the Bean
    Validation API. If the constraints are violated then the
    resource method is not invoked and instead a response with
    status code 400 (Bad Request) and an entity that describe the
    violations is returned to the client.



    Here is a sample code of how to validate request entity bodies
    when they are mapped to resource method parameters:



    @CheckProduct

    class Product { . . . }



    @Path("/")

    class ProductResource {



        @POST

        @Consumes(MediaType.APPLICATION_JSON)

        public void addProduct(@Valid Product
    product) {

            . . .

        }

    }




    The presence of @Valid (a pre-defined annotation
    in Bean Validation API) next to the method parameter ensures
    that the @CheckProduct constraint is called to
    verify the mapped entity.



    The JAX-RS specification also defines the sequence to validate
    root resource class instances. The recommendation is to return
    as many violations as possible instead of aborting after the
    first violation is encountered.

  • Asynchronous Processing:
    JAX-RS 2.0 introduces asynchronous processing on server- and
    client-side APIs for the usual reasons. The server-side code
    will look like:



    @Path("/async")

    class ProductResource {

        @Context ExecutionContext ctx;



        @GET

        @Suspend

        public Product longOp() {

           
    Executors.newSingleThreadExecutor().submit(

               
    new Runnable() {

                   
    public void run() {

                       
    Proruct product = longQueryFromDatabase();

                       
    ctx.resume(product);

                   
    }

               
    }

            );

        }

    }



    The longOp method is invoked when this resource is
    accessed using GET, forks a new thread, and returns immediately
    without producing the result. Once longQueryFromDatabase
    returns the product then the connection is resumed and the
    response is returned by calling ctx.resume and
    setting the value.



    ExecutionContext also provide suspend()
    that allows to override the values, such as timeout, specified
    in the annotation based upon the runtime state.



    On the client-side, the code will look like:



    Client client = ClientFactory.newClient();

    Future<String> future =
    client.target("http://.../atm/{card}/balance")

                         
            .pathParam("card",
    "1111222233334444")

           
                         
    .queryParam("pin", "1234")

           
     
         
                   
    .request("text/plain")

                  
     
         
            
    .async()

                         
     
         
      .get();



    The async() is called during building the client
    request. The return Future<String> can be
    used to query/cancel the status of execution on the server-side
    using isDone and cancel. Once the
    response is ready then Future<T>.get() is
    invoked to receive an instance of T if the
    response was successful or null if the invocation failed.



    Optionally an InvocationCallback<T> may be
    registered during the request invocation. The completed
    method is called when the invocation completes successfully and
    a response is available and failed method is
    called when the invocation fails. The code looks like:



    Future<String> future =
    client.target("http://.../atm/{card}/balance")

                         
            .pathParam("card",
    "1111222233334444")

           
                         
    .queryParam("pin", "1234")

           
     
         
                   
    .request("text/plain")

                  
     
         
            
    .async()

                         
     
         
      .get(

                                     
    new InvocationCallback<String>() {

                                         
    @Override

                                         
    public void completed(String result) {

                                             
    // got the correct result

                                             
    System.out.println(result);


                                         
    }




                                         
    @Override

                                         
    public void failed(InvocationException error) {

                                             
    // ouch, got an error!


                                             
    System.err.println(error.getCause());


                                         
    }


                                     
    }

                                  
    );




    Notice, the type of the result is specified as type parameter to
    InvocationCallback.

    Client and server developers optimize their resources (threads) depending upon their needs and are independent of each other. A client really can't tell if a resource is implemented asynchronously or not and shouldn't even need to know.

  • Improved connection
    negotiation
    : This would allow a server to specify a
    preferred MIME type if the client does not care about it. This
    can be easily specified using the "qs" qualifier as shown below:



    @Path("/")

    class ProductResource {



        @GET

        @Produces({ "text/xml
    ;qs=0.75",
    "application/json"})

        public Product[] getProducts() {

            . . .

        }

    }




    The default server-side qs-value and the final order of
    server-side served types preferences follow the same rules as
    those specified for href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">HTTP
    Accept Header. Per those rules an unspecified value takes
    the default value of 1. So the above @Produces
    rule says "application/json" will be served as the preferred
    type if there is no Accept header from the client.
    The section 3.5 talks more about qs parameter and
    the section 3.8 in the specification provide complete details
    about how media type of the response is chosen by a JAX-RS
    runtime.

The Appendix D in the specification provide a comprehensive list
of changes from the previous version of the specification.

Here are some final set of references for you:

  • href="http://jcp.org/aboutJava/communityprocess/edr/jsr339/index.html">JAX-RS
    2.0 Specification
  • href="http://jax-rs-spec.java.net/nonav/2.0/apidocs/index.html">Javadocs
  • JAX-RS
    Specification Wiki
  • href="http://java.net/projects/jax-rs-spec/sources/git/show">JAX-RS
    Workspace (including API and javadocs)


And of course, it'll all be delivered as part of GlassFish 4.0!

Learn the latest and greatest about JAX-RS 2.0 from Marek
Potociar's talk on JAX-RS at Devoxx 2011:

value="http://www.parleys.com/dist/share/parleysshare.swf"> name="allowFullScreen" value="true"> value="direct"> name="flashVars" value="sv=true&pageId=2820"> src="http://www.parleys.com/dist/share/parleysshare.swf"
type="application/x-shockwave-flash"
flashvars="sv=true&pageId=2820" allowfullscreen="true"
bgcolor="#222222" height="395" width="395">

Join the discussion

Comments ( 2 )
  • web tasar&#305;m Tuesday, February 7, 2012

    good news about Java EE 7 Making Progress


  • Aaron Knauf Friday, November 2, 2012

    A minor point - but significant in the REST world: the mention of the term "atm" in your url seems to be talking about the RESTful service itself and not a resource that you are manipulating. If you were naming a particular atm, which you were going to drive with this service, then that might be useful. In this case, it I think it would be more RESTfully correct to talk about the resource that you are manipulating - perhaps the bank account?

    Also, the use of the term "withdraw" - being a verb - does not really denote a resource. You might possibly POST a withdrawal transaction to your bank account resource instead?


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services