Examples for Chapter 9 - JAX-RS Workbook - RESTful Java with JAX-RS 2.0 (2013)

RESTful Java with JAX-RS 2.0 (2013)

Part II. JAX-RS Workbook

Chapter 23. Examples for Chapter 9

In Chapter 9, you learned that clients can use HTTP Content Negotiation to request different data formats from the same URL using the Accept header. You also learned that JAX-RS takes the Accept header into account when deciding how to dispatch an HTTP request to a Java method. In this chapter, you’ll see two different examples that show how JAX-RS and HTTP conneg can work together.

Example ex09_1: Conneg with JAX-RS

This example is a slight modification from ex06_1 and shows two different concepts. First, the same JAX-RS resource method can process two different media types. Chapter 9 gives the example of a method that returns a JAXB annotated class instance that can be returned as either JSON or XML. We’ve implemented this in ex09_1 by slightly changing the CustomerResource.getCustomer() method:

src/main/java/com/restfully/shop/services/CustomerResource.java

@Path("/customers")
public class CustomerResource {
...
   @GET
   @Path("{id}")
   @Produces({"application/xml", "application/json"})
   public Customer getCustomer(@PathParam("id") int id)
   {
      ...
   }

The JAXB provider that comes with RESTEasy can convert JAXB objects to JSON or XML. In this example, we have added the media type application/json to getCustomer()’s @Produces annotation. The JAX-RS runtime will process the Accept header and pick the appropriate media type of the response for getCustomer(). If the Accept header is application/xml, XML will be produced. If the Accept header is JSON, the Customer object will be outputted as JSON.

The second concept being highlighted here is that you can use the @Produces annotation to dispatch to different Java methods. To illustrate this, we’ve added the getCustomerString() method, which processes the same URL as getCustomer() but for a different media type:

   @GET
   @Path("{id}")
   @Produces("text/plain")
   public Customer getCustomerString(@PathParam("id") int id)
   {
      return getCustomer(id).toString();
   }

The Client Code

The client code for this example executes various HTTP GET requests to retrieve different representations of a Customer. Each request sets the Accept header a little differently so that it can obtain a different representation. For example:

src/test/java/com/restfully/shop/test/CustomerResourceTest.java

public class CustomerResourceTest
{
   @Test
   public void testCustomerResource() throws Exception
   {
      ... initialization code ...
 
      System.out.println("*** GET XML Created Customer **");
      String xml = client.target(location).request()
                                .accept(MediaType.APPLICATION_XML_TYPE)
                                .get(String.class);
      System.out.println(xml);
 
      System.out.println("*** GET JSON Created Customer **");
      String json = client.target(location).request()
              .accept(MediaType.APPLICATION_JSON_TYPE)
              .get(String.class);
      System.out.println(json);
   }
}

The SyncInvoker.accept() method is used to initialize the Accept header. The client extracts a String from the HTTP response so it can show you the request XML or JSON.

Build and Run the Example Program

Perform the following steps:

1. Open a command prompt or shell terminal and change to the ex09_1 directory of the workbook example code.

2. Make sure your PATH is set up to include both the JDK and Maven, as described in Chapter 17.

3. Perform the build and run the example by typing maven install.

Example ex09_2: Conneg via URL Patterns

Chapter 9 discussed how some clients, particularly browsers, are unable to use the Accept header to request different formats from the same URL. To solve this problem, many JAX-RS implementations allow you to map a filename suffix (.html, .xml, .txt) to a particular media type. RESTEasy has this capability. We’re going to illustrate this using your browser as a client along with a slightly modified version of ex09_1.

The Server Code

A few minor things have changed on the server side. First, we add getCustomerHtml() method to our CustomerResource class:

   @GET
   @Path("{id}")
   @Produces("text/html")
   public String getCustomerHtml(@PathParam("id") int id)
   {
      return "<h1>Customer As HTML</h1><pre>"
                   + getCustomer(id).toString() + "</pre>";
   }

Since you’re going to be interacting with this service through your browser, it might be nice if the example outputs HTML in addition to text, XML, and JSON.

The only other change to the server side is in the configuration for RESTEasy:

src/main/webapp/WEB-INF/web.xml

<web-app>
 
    <context-param>
        <param-name>resteasy.media.type.mappings</param-name>
        <param-value>
                html : text/html,
                txt : text/plain,
                xml : application/xml
        </param-value>
    </context-param>
...
</web-app>

The resteasy.media.type.mappings content parameter is added to define a mapping between various file suffixes and the media types they map to. A comma separates each entry. The suffix string makes up the first half of the entry and the colon character delimits the suffix from the media type it maps to. Here, we’ve defined mappings between .html and text/html, .txt and text/plain, and .xml and application/xml.

Build and Run the Example Program

Perform the following steps:

1. Open a command prompt or shell terminal and change to the ex09_2 directory of the workbook example code.

2. Make sure your PATH is set up to include both the JDK and Maven, as described in Chapter 17.

3. Perform the build and run the example by typing maven jetty:run.

The jetty:run target will run the servlet container so that you can make browser invocations on it. Now, open up your browser and visit http://localhost:8080/customers/1.

Doing so will show you which default media type your browser requests. Each browser may be different. For me, Firefox 3.x prefers HTML, and Safari prefers XML.

Next, browse each of the following URLs: http://localhost:8080/customers/1.html, http://localhost:8080/customers/1.txt, and http://localhost:8080/customers/1.xml. You should see a different representation for each.