IgorShare Thoughts and Ideas

Consulting and Training

Building GWT web clients [Part 2] – How to expose REST-full JAX-RS service with Jersey on Tomcat server?

Posted by Igor Moochnick on 05/20/2009

In the previous article (Part 1) we’ve seen how to create a web-based REST-full client (and an appropriate server) by using GWT. GWT is not providing any “standard” REST (if you can use this word in REST context at all) interface, but, merely, exposes the server-side logic via a proprietary GWT RPC interface.

Today, the most common REST standard is the JAX-RS specification. By implementing your code along the JAX-RS guidelines you can be rest assured that you can easily switch one REST-RX library with another.

As of today there are a couple of JAX-RS libraries used by the Java community:

  1. Jersey
  2. Restlet
  3. Portlet
  4. etc…

On the other hand, being a big fan of Spring, I was hoping that Spring will provide the JAX-RS support in it’s Spring v3 release, but, looking at the M3 drop, I have realized that it’s nowhere near that promise (check my discussion on the StackOverflow).

For this post I’m going to use Jersey JAX-RS implementation. Let’s start with creating

a Dynamic Web Project in Eclipse. I’m going to use:

  1. Apache Tomcat v6.0
  2. Dynamic Web Module v2.5
  3. Default Configuration for Apache Tomcat v6.0

To add Jersey (1.1.0-ea) into this mix, add the following JARs (from this obscure installation instructions page) to your build path:

  1. asm-3.1.jar
  2. jsr311-api-1.1.jar
  3. jersey-bundle-1.1.0-ea.jar
  4. jersey-json-1.1.0-ea.jar
  5. jaxb-impl-2.1.10.jar

Don’t forget to add these JARs to the “Java EE Module Dependencies” (in the properties of the project) as well.

Let’s define our Web Service. By using the JAX-RS specification it becomes extremely easy:

@PerRequest 
@Path("/contacts") 
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) 
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) 
public class ContactManagerService { 
    final static List<ContactInfo> contacts = new ArrayList<ContactInfo>(); 
    static { 
        contacts.add(new ContactInfo("Joe", "Simth", "Some Company")); 
        contacts.add(new ContactInfo("Tom", "Doe", "Another Company")); 
    } 

    @GET 
    public ContactList getAllContacts() 
    { 
        return contacts; 
    } 

    @GET 
    @Path("{filter}") 
    public ContactList getFilteredContacts(@PathParam("filter") String filter) 
    { 
        ...

        return ContactList.fromContacts( contacts ); 
    } 

}

A couple of things to notice here:

  1. The “root” path to the ContactManager Web service marked by tompost annotation @Path("/contacts"), is: /contacts
  2. This class returns data in both application/json and application/xml formats. This is defined by the @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) annotations.
  3. The “default” method for this web service is “getAllContacts”. This is happening because this method has NO @Path annotation.
  4. The “getFilteredContacts” will be called if the Web Services URL will contain a non-empty addition to the root URL, like this: /contact/joe
    1. Note that this addition should be URL-encoded
    2. If you’d like to replace it with the query param – replace the annotation with the @QueryParam one. In this case the call will look like /contacts?filter=joe

The ContactList, that is returned to the client, should be annotated with @XmlRootElement so Jetty will fire up an appropriate the JAXB provider for the serialization (we’ll talk more about providers later):

@XmlRootElement 
public class ContactList { 

    @XmlElement 
    protected java.util.List<ContactInfo> contacts; 

    public ContactList() { ... }

}

As you can guess, there is no magic in the world (I, actually, still hope that there is some 😉 so, to make our service visible to the outside world, we need to make sure that Tomcat loads Jersey which, in its order, will load and expose our service according to our annotations. This is done via the additional configuration in the web.config file:

<!-- Servlets --> 
<servlet> 
    <servlet-name>ContactManager Web Services</servlet-name> 
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>  
    <load-on-startup>1</load-on-startup> 
</servlet> 
<servlet-mapping> 
    <servlet-name>ContactManager Web Services</servlet-name> 
    <url-pattern>/services/*</url-pattern> 
</servlet-mapping>

After completing all the above you can start Tomcat and use any of the available REST test clients like Fiddler, RESTClient or RESTTest (see discussion on StackOverflow) to see our service in action.

The root URL to the ContactManagerService is http://localhost:8080/ContactManagerServer/services/contacts.

If the request will contain header “Accept: application/json” the result will look like this:

{"contacts":[{"FirstName":"Joe","LastName":"Simth","Company":"Some Company"},
{"FirstName":"Tom","LastName":"Doe","Company":"Another Company"}]}

On the other hand the header “Accept: application/xml” will produce result like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contactList>
	<contacts><FirstName>Joe</FirstName><LastName>Simth</LastName><Company>Some Company</Company></contacts>
	<contacts><FirstName>Tom</FirstName><LastName>Doe</LastName><Company>Another Company</Company></contacts>
</contactList>

Disregard format of the returned content for a moment, we’re going to talk about serialization in later posts.

More information about the JSON support in Jersey can be found in the Jersey User Guide.

6 Responses to “Building GWT web clients [Part 2] – How to expose REST-full JAX-RS service with Jersey on Tomcat server?”

  1. Navneet said

    It is really very good tutorial.
    Thanks a lot for such kind of help.

  2. BillG said

    This tutorial and the last one are both very helpful, thanks. One thing that would be useful though would be to show how the GWT client would interact with the XML REST interface. You provide a good example of GWT-RPC, followed by REST via JAX-RS, but you don’t show how to tie them together with GWT using REST.

    • David said

      Seconded. I’d like to have one server implementation (in REST) and then have the GWT client use it as well as have it available exposed for web services.

  3. Hi Igor,

    As you mentioned, Restlet has support for the JAX-RS API, via an extension module. But the Restlet Framework also comes with its own Restlet API, which is both client and server side capable, and is much more complete than JAX-RS. It comes with simpler annotations than JAX-RS in Restlet 2.0 and provides an extensive support for GWT/GAE/Android, with the generation of proxies based on annotated Java interfaces in the recent snapshots (same productivity as GWT-RPC), see this related post:

    “Restlet, a RESTful middleware for GWT, GAE and Android”
    http://blog.noelios.com/2009/12/17/restlet-a-restful-middleware-for-gwt-gae-and-android/

    Best regards,
    Jerome Louvel
    http://www.restlet.org

  4. Server…

    […]Building GWT web clients [Part 2] – How to expose REST-full JAX-RS service with Jersey on Tomcat server? « IgorShare Weblog[…]…

  5. Vikram said

    Thanks Igor for sharing this.

    Can we also expose the GreetingServiceImpl(generated as part of sample class in GWT project) as a web service using the above method. I did tried that , but getting 404 error.

Leave a comment