Content received from: http://JavaFAQ.nu/java-article1175.html


Implementing RESTful Web Services in Java
Wednesday, December 12, 2007 (21:20:10)

Posted by jalex

This Tech Tip will show you how to write RESTful web services in Java that conform to the JAX-RS: Java API for RESTful Web Services (JSR-311) specification and its reference implementation - Jersey. You'll learn some of the principles of Representational State Transfer (REST) and get introduced to JAX-RS and Jersey.

The tip uses a sample application to demonstrate some of the JAX-RS concepts and techniques. You can obtain the sample by downloading the latest Jersey snapshot from the Jersey downloads page. The code examples in the tip are taken from the source code of the sample application (which is included in the download package).



This tip was originally published by Sun Microsystems and republished here with the permission.

Welcome to the Enterprise Java Technologies Tech Tips for November 16, 2007. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE).

You can now read the Enterprise Java Technologies Tech Tips online as a web log.

This tip covers Implementing RESTful web services in Java.

The tip was developed using an open source reference implementation of Java EE 5 called GlassFish, and the open source NetBeans IDE 5.5.1. You can download GlassFish from the GlassFish Community Downloads page. You can download the NetBeans IDE 5.5.1 from the NetBeans page.

Any use of this code and/or information below is subject to the license terms.

Implementing RESTful Web Services in Java

By Jakub Podlesak and Paul Sandoz

This Tech Tip will show you how to write RESTful web services in Java that conform to the JAX-RS: Java API for RESTful Web Services (JSR-311) specification and its reference implementation - Jersey. You'll learn some of the principles of Representational State Transfer (REST) and get introduced to JAX-RS and Jersey.

The tip uses a sample application to demonstrate some of the JAX-RS concepts and techniques. You can obtain the sample by downloading the latest Jersey snapshot from the Jersey downloads page. The code examples in the tip are taken from the source code of the sample application (which is included in the download package).

An Introduction to RESTful Web Services

Representational State Transfer (REST) is a style of software architecture for distributed systems such as the World Wide Web. The term was introduced in the doctoral dissertation of Roy Fielding in 2000, and has since come into widespread use in the networking community. An important concept in REST is the existence of resources, each of which can be referred to using a global identifier, that is, a URI. In order to manipulate these resources, components of the network, clients and servers, communicate using a standardized interface such as HTTP and exchange representations of these resources.

RESTful web services are services built using the RESTful architectural style. Building web services using the RESTful approach is emerging as a popular alternative to using SOAP-based technologies for deploying services on the Internet, due to its lightweight nature and the ability to transmit data directly over HTTP.

RESTful Web Service Principles

A RESTful web service is based on the following principles:

  • Resources and representations. Instead of providing just one endpoint for a particular web service and having that endpoint perform various operations, you provide access to resources. A resource is a single piece of your web application that you make accessible to clients. Because the resources you have are not transportable over the network, "providing them" means providing representations of their state.

  • Addressability and connectedness. Resources have their representations, but providing representations of resources would be useless if you could not address them. In REST, every resource must have at least one address, that is, one URI. To address the resource, you simply specify the URI. This concept is called "addressability". By publishing your web application, you introduce many different URIs that are connected to each other. Because of that connectedness, the only URI you need to give to your clients is one URI called the "bootstrap URI".

  • Uniform interface. Even if you make resources available through URIs and representations to exchange between the client and server, it still does not allow you to establish communication. You need a communication protocol/interface to use. In a REST architecture, such an interface must be uniform. It means that whatever URI you access, the interface should be the same. For instance, on the World Wide Web no matter what URI (resource address) you enter, your web browser simply uses an HTTP GET method to retrieve a corresponding web page (resource representation) and displays it.

  • Statelessness. Statelessness means that a web application is not responsible for keeping any information about the state of its clients. REST does not encompass the concept of HTTP sessions. The client is responsible for tracking its own actions (if it needs to). The service maintains its resources and provides a uniform interface to the clients.

JAX-RS and Jersey

JAX-RS provides a standardized API for building RESTful web services in Java. The API basically provides a set of annotations and associated classes and interfaces. Applying the annotations to Plain Old Java Objects (POJOs) enables you to expose web resources. The API is not yet complete. The final version should become part of Java EE 6. You can find more information about JAX-RS in the jsr311 project.

Jersey is a reference implementation of JAX-RS. You can find downloadable distributions of Jersey on the Jersey project downloads page. If you select the latest Jersey snapshot and unzip it, you will see that the Jersey implementation is bundled with several examples demonstrating its use. Let's examine one of those examples.

An Example of JAX-RS in Use: The Bookmark Application

One of the examples distributed with Jersey is a bookmark application. You'll find it in the examples/Bookmark subdirectory. The application uses the JAX-RS API to maintain information about bookmarks saved by users. If you run the application and specify a specific user, the application returns data similar to the following:

   {sdesc":"test desc","userid":"testuserid","uri":
   "http://java.sun.com","ldesc":"long test description"}

Notice that the application returns the data in JavaScript Object Notation (JSON) format.

If you navigate below the examples/Bookmark subdirectory to the resources subdirectory, you'll find the following resources for the application:

  • UsersResource: Represents a list of users
  • UserResource: Represents a specific user
  • BookmarksResource: Represents a list of bookmarks for a specific user
  • BookmarkResource: Represents a specific bookmark

Recall that to address a resource in REST you specify its URI. However, to communicate with a resource, you also need to specify a communication protocol such as HTTP. Here are the URIs and HTTP methods that correspond to the resources in the Bookmark application:

 
Resource
URI Path
HTTP Methods
UsersResource
/users
GET
UserResource
/users/{userid}
GET, PUT, DELETE
BookmarksResource
/users/{userid}/bookmarks
GET, POST
BookmarkResource
/users/{userid}/bookmarks/{bmid}
GET, PUT, DELETE

To understand some of the basics of the JAX-RS, let's look at two of these resources: UsersResource and UserResource.

UsersResource

Here is a snippet of source code from the UsersResource class:

Code:

@UriTemplate("/users/")

   public class UsersResource {
     
       @HttpContext UriInfo uriInfo;   

       @PersistenceUnit(unitName = "BookmarkPU")
       EntityManagerFactory emf;

       /** Creates a new instance of Users */
       public UsersResource() {
       }
   
       public List<UserEntity> getUsers() {
           return emf.createEntityManager().createQuery(
                  "SELECT u from UserEntity u").getResultList();
       }
   
       @UriTemplate("{userid}/")
       public UserResource getUser(@UriParam("userid")
              String userid) {
           return new UserResource(
                  uriInfo, emf.createEntityManager(), userid);
       }

       @HttpMethod("GET")
       @ProduceMime("application/json")
       public JSONArray getUsersAsJsonArray() {
           JSONArray uriArray = new JSONArray();
           UriBuilder ub = null;
           for (UserEntity userEntity : getUsers()) {
               ub = (ub == null) ?
                      uriInfo.getBuilder() : ub.clone();
               URI userUri = ub.
                       path(userEntity.getUserid()).
                       build();
               uriArray.put(userUri.toString());
           }
           return uriArray;
       }
   }

Notice that the UsersResource class is annotated by the @UriTemplate("/users/") annotation. @UriTemplate is a JAX-RS annotation that identifies the URI path for the resource. Here the annotation identifies the URI path as /users/:

   @UriTemplate("/users/")

Annotating the class with a @UriTemplate annotation makes the class a "Root resource class." It also means that for client requests that access the /users/ URI path, this resource is responsible for providing appropriate responses. Note too that the /users/ URI path is the bootstrap URI path for the entire Bookmark web application.

Another JSR-311 annotation in the UsersResource class is @HttpContext.

   @HttpContext UriInfo uriInfo;

This annotation injects information into a class field or method parameter. In the UsersResource class, @HttpContext injects information about the URI into the uriInfo variable, which is then available to provide pertinent information about the URI.

UsersResource Methods

The UsersResource class has two methods, getUser and getUsersAsJsonArray. For the moment, let's skip getUser and focus on getUsersAsJsonArray. The getUsersAsJsonArray method returns the URIs for all user resources. Notice that the method is annotated with two JSR 311 annotations: @HttpMethod and @ProduceMime. The @HttpMethod annotation indicates that the annotated method should be used to handle HTTP requests. The annotation also specifies the type of HTTP request to which the method will respond. In this example, the annotation specifies that the getUsersAsJsonArray method serves HTTP GET requests.

   @HttpMethod("GET")

Methods like this that serve REST requests are called "Resource methods".

The @ProduceMime annotation specifies the MIME types that a method can produce. Here, the annotation specifies that the getUsersAsJsonArray method returns a JSONArray object containing an array of URIs for all existing user resources.

   @ProduceMime("application/json")

Get Users Resources
Get Users Resources
 

The JSON array object that the method returns to a client might look like this:

   ["http://localhost:8080/Bookmark/resources/users/joe", 
   "http://localhost:8080/Bookmark/resources/users/mary"]

This JSON array contains URIs, that is, links, to two user resources, joe and mary.

The getUser method gets information about a specific user. For example, if a client wants to get information about user joe, the client accesses the resource at its URI -- in this case, http://localhost:8080/Bookmark/resources/users/joe. Recall that the UsersResource class serves all requests for paths beginning with /users/, including the URI path for joe, that is, /users/joe.

Here it's important that the getUser method is annotated with @UriTemplate("{userid}/"). This makes the method a "Sub-resource locator". Also the getUser method is annotated with @UriParam. As a result, when the getUser method is invoked, a userid from the current request URI path is injected into the userid parameter.

Notice that there is no @HttpMethod annotation associated with the getUser method. Because of that, the output of the method is considered a Resource class object. This means that request processing will be delegated to the Resource class and appropriate @HttpMethod-annotated methods will be looked up there. Because the getUser method returns a UserResource object:

   public UserResource getUser(@UriParam("userid") 
                 String userid) {
           return new UserResource(...)

an appropriate method in the UserResource class is invoked.

Get User Resources
Get User Resources
 

UserResource

As just mentioned, request processing for the getUser method in the UsersResource class is delegated to an appropriate method in a newly instantiated UserResource object. Here is a snippet of code from the UserResource class showing one of its methods, getUser.

Code:



 @HttpMethod("GET")
   @ProduceMime("application/json")
   public JSONObject getUser() throws JSONException {
       if (null == userEntity) {
           throw new NotFoundException(
                  "userid " + userid + "does not exist!");
       }
       return new JSONObject()
           .put("userid", userEntity.getUserid())
           .put("username", userEntity.getUsername())
           .put("email", userEntity.getEmail())
           .put("password", userEntity.getPassword())
           .put("bookmarks",
                uriInfo.getBuilder().path("bookmarks").build());
    }
               

Notice that this method also is annotated by @HttpMethod("GET") and @ProduceMime("application/json"). Here the getUsers method serves HTTP GET requests and returns a JSONObject object. The JSONObject object contains a representation of a particular user, for instance, the representation of the user whose userid is joe.

You're encouraged to examine the rest of the source code in UserResource. You'll notice additional JSR 311 annotations, such as @ConsumeMime, which identifies the MIME types that a method can accept.

Building and Deploying the Sample Code

The sample code for the tip is available as a NetBeans project. You can build an deploy the sample from the NetBeans IDE or from the command line. In either case:

  1. If you haven't already done so, download and install GlassFish V2.

  2. Download the latest Jersey snapshot from the Jersey downloads page and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/jersey, where <sample_install_dir> is the directory where you installed the sample application. For example, if you extracted the contents to C:\ on a Windows machine, then your newly created directory should be at C:\jersey.

Building and Deploying the Sample Code in NetBeans

  1. If you haven't already done so, download and install the NetBeans 5.5.1 IDE.

  2. Start the NetBeans IDE. If you haven't already done so, register GlassFish V2 in NetBeans as follows:

    • Right click on Servers node in the Runtime window.
    • Select Add Server.
    • Leave the Server as Sun Java System Application Server.
    • Click the Next button.
    • Click the Browse button and browse to the location that you installed GlassFish V2.
    • Click the Choose button.
    • Click the Next button.
    • Set the Admin Password to the default, adminadmin, unless you chose a different password for GlassFish.
    • Click the Finish button.

  3. Open the Bookmark project as follows:

    • Select Open Project from the File menu.
    • Browse to the Bookmark subdirectory.
    • Click the Open Project Folder button.

  4. Build and deploy the Bookmark project as follows:

    • Right click the Bookmark project node in the Projects window.
    • Select Deploy Project or press F6 (Run Main Project).

Building and Deploying the Sample Code From the Command Line

  1. Set the AS_HOME environment variable to the GlassFish v2 installation directory, for example, (here shown in bash syntax):

          export AS_HOME= <GF_install_dir>

    where <GF_install_dir> is the directory where you installed GlassFish v2.

  2. Navigate below the <sample_install_dir>/jersey directory to the /examples/Bookmark directory. Build the Bookmark application by entering the following command on the command line (here shown in bash syntax):

          AS_HOME/lib/ant/bin/ant run-on-glassfish

Running the Sample Code

You can run the deployed Bookmark application as follows using Curl, a command line HTTP tool.

  1. If you haven't already done so, download Curl.

  2. Add a new user by entering the following command on the command line (note that the commands in this and subsequent steps are shown on multiple lines for formatting purposes):

          curl -i --data "{\"userid\":\"techtip\",\"username\":
          \"TechTip User\",\"email\":\"techtip@example.com\",
          \"password\":\"TEST\"}" -H Content-type:application/json 
          -X PUT 
          http://localhost:8080/Bookmark/resources/users/techtip/

    In response, an HTTP GET request is dispatched to the getUser method in the UsersResource class, which instantiates a new UserResource object. The request is further dispatched to the putUser method.

    You should see output similar to the following:

          HTTP/1.1 204 No Content
          X-Powered-By: Servlet/2.5
          Server: Sun Java System Application Server 9.1_01
          Date: Thu, 01 Nov 2007 14:31:53 GMT

  3. Get a list of users by entering the following command on the command line:

          curl -i -X GET 
          http://localhost:8080/Bookmark/resources/users/

    This invokes the getUsersListAsJson method of the UsersResource class.

    You should see output similar to the following:

          HTTP/1.1 200 OK
          X-Powered-By: Servlet/2.5
          Server: Sun Java System Application Server 9.1_01
          Content-Type: application/json
          Transfer-Encoding: chunked
          Date: Thu, 01 Nov 2007 14:34:07 GMT

          ["http:\/\/localhost:8080\/Bookmark\/resources\/users\
          /techtip"]

  4. Get the representation of a user by entering the following command on the command line :

          curl -i -X GET 
          http://localhost:8080/Bookmark/resources/users/techtip/

    The resulting actions here are similar to those for step 2.

    You should see output similar to the following:

          HTTP/1.1 200 OK
          X-Powered-By: Servlet/2.5
          Server: Sun Java System Application Server 9.1_01
          Content-Type: application/json
          Transfer-Encoding: chunked
          Date: Thu, 01 Nov 2007 14:35:38 GMT

          {"userid":"techtip","username":"TechTip User",
          "email":"techtip@example.com","password":"TEST",
          "bookmarks":"http:\/\/localhost:8080\/Bookmark\/resources
          \/users\/techtip\/bookmarks"}

Summary

This tip demonstrated how you can write RESTful web services in Java that conform to the JAX-RS: Java API for RESTful Web Services (JSR-311) specification. You can learn more about JAX-RS in the jsr311 project. You can learn more about Jersey, the reference implementation of JAX-RS, in the Jersey project.

About the Authors

Jakub Podlesak is a member of the Jersey project team. Previously, he participated in the development of Metro, the GlassFish v2 web services stack, as a member of the WS-Policy team.

Paul Sandoz is the co-spec lead and implementation lead for JSR 311: Java API for RESTful Web Services. He has participated in the W3C, ISO, and ITU-T standards organizations and contributed various performance-related technologies and improvements to the GlassFish web services stack, particularly in standardization, implementation, integration, and interoperability of Fast Infoset.