Getting Started With RESTful Web Services Development.

This document describes an early access implementation of a Java API for RESTful web services development.

The goal of the API is to provide a programming model that enables developers to rapidly build web services in Java (or using the Java Virtual Machine) that are characteristic of the best designed parts of the web. The API and programming model encourage the use of the REST architectural style and the correct use of HTTP 1.1.

The implementation of the API is commonly referred to as a 'runtime'. The runtime is responsible for deploying Plain Old Java Objects (POJOs), which conform to the API and programming model, and dispatching HTTP requests to those Java objects.

The API

The Java documentation for the API can be found here.

Creating a RESTful Web Service

Joe Gregorio in his article "How to Create a REST Protocol" presents a prescriptive approach for creating a RESTful Web service. This is an effective way of tackling the problem, so this section follows suit, using the simple employee service example presented in the article to create a RESTful Web service using the API.

Using the prescribed approach, a set of questions are asked in the following order:

  1. What are the URIs?
  2. What's the format?
  3. What methods are supported at each URI? 
  4. What status codes could be returned?

What Are the URIs?

This question really means: What are the resources that are identified by the URIs? Using the API, the question becomes: What are the Java classes corresponding to the resources that are identified by the URIs? The simple example presents two resources:

  1. Employee (one URI per employee) 
  2. All employees

Java classes corresponding to resources are annotated with the UriTemplate annotation. The example below shows the employees and employee resources as two Java classes:

@UriTemplate("/employees")
public class Employees { ... }
@UriTemplate("/employee/{id}")
public class Employee { ... }

The UriTemplate annotation defines a URI template as a URI path relative to the base URI of the container. URI Template is an Internet-Draft that specifies URI templates to be:

"strings that can be transformed into URIs after embedded variables are substituted. This document defines the structure and syntax of URI Templates."

The API uses URI templates in reverse. Given a set of UriTemplate annotated Java classes and a URI of an HTTP request, the runtime deploying the Java classes, will, on receiving the HTTP request, find the most specific Java class whose URI template matches the URI path of the HTTP request.

NOTE: The matching algorithm of an HTTP request to a Java class is more involved than just matching the URI template as described in this section. It also matches additional properties such as the HTTP method, the media type of the HTTP request, and the acceptable media types for the HTTP response.

Assuming that the Java classes are deployed to the base URI http://example.com/ then the following URIs will match the URI template "/employee/{id}" of the Employee class:

http://example.com/employee/1234
http://example.com/employee/johnDoe
http://example.com/employee/john/doe

Where the id variable is substituted, respectively, with the strings "1234", "johnDoe" and "john/doe". So the Employee class matches many URIs, as many as there are employees. Whereas only the URI http://example.com/employees will match the URI template "/employees" of the Employees class.

What's the Format?

This question really means: What does a resource consume in terms of HTTP request entities and produce in terms of HTTP response entities, the latter of which are referred to as representations? Or more simply put: What is the information that can be sent and received?

HTTP request entities and representations are identified by MIME media types. (Such MIME media types are used for the Content-Type HTTP header request/response field or the Accept HTTP header request field.) The API specifies annotations for declaring what MIME media types may be consumed (from an HTTP request entity) and produced (by a representation).

The example below shows the Employees and Employee classes annotated with a ConsumedMime and ProduceMime annotation:

@UriTemplate("/employees")
@ConsumeMime("application/employee+xml")
@ProduceMime("application/employee+xml")
public class Employees { ... }
@UriTemplate("/employee/{id}")
@ConsumeMime("application/employee+xml")
@ProduceMime("application/employee+xml")
public class Employee { ... }

These annotiations declare that the resources consume and produce information identified by the MIME media type application/employee+xml. Declaring such annotations on the Java class states that by default all HTTP methods (see next section) are declared to consume or produce the MIME media types. More than one MIME media type may be consumed or produced by declaring a comma separated list of MIME media types. It is also possible to specify the media type at the method level as shown below.

What methods are supported at each URI?

HTTP methods are mapped to Java class methods using the HttpMethod annotation. The Java method arguments are populated with information from the HTTP request, and the Java method return value becomes the HTTP response. The example below shows the Employees class that supports the HTTP GET method to obtain a list of employees, and the HTTP POST method to add a new employee.

@UriTemplate("/employees")
@ConsumeMime("application/employee+xml")
@ProduceMime("application/employee+xml")
public class Employees {

  @HttpMethod
  public Employees getEmployeeList() {
    Employees es = ...
    return es;
  }

  @HttpMethod("POST")
  public Employee createEmployee(
      Employee employee) {
    ...
    return new employee;        
  }
}

The names of the Java methods annotated with HttpMethod are not significant when an argument is supplied with the annotation, otherwise the Java method must begin with a valid and known HTTP method. The Java method may return void, T, Representation<T> (or an extension of), HttpResponse (or an extension of) or Object that is any type of the former (except void).

Methods that expect an HTTP body (usually PUT or POST) should have a method argument of type T or Entity<T> to accept the HTTP body content, where T is the desired format. In this example, we are using JAXB to convert between the on-the-wire XML data and a Java class representation of the data.

The API provides support for a number of useful formats:

com.sun.jersey.api.representation
This package contains a set of classes that implement Representation<T> for a variety of T. You can use these classes for returning data from a method, or develop your own custom class that implements Representation<T> and return an instance of that class instead. The AbstractRepresentation<T> class is provided to simplify the implementation of a custom representation.
InputStream, String, byte[], DataSource, File, MimeMultipart, FormURLEncodedProperties, Entry (ROME library), Feed (ROME library) and JAXB classes
These classes can all be used as the T for a return type or a method parameter, Representation<T> for a return type, or Entity<T> for a method parameter. See com.sun.jersey.spi.streaming.TypeStreamingProvider for documentation that describes how to add your own custom streaming provider to API.

The example below shows the Employee class that supports the HTTP GET method to obtain an employee, the HTTP PUT method to update an employee, and the HTTP DELETE method to delete an employee:

@UriTemplate("/employee/{id}")
@ConsumeMime("application/employee+xml")
@ProduceMime("application/employee+xml")
public class Employee {

  @HttpMethod
  public Employee getEmployee(
      @UriParam("id") int id) {
    Employee e = ...
    return e;
  }
  
  @HttpMethod
  public void putEmployee(
      @UriParam("id") int id,
      Employee employee) {
    ...
  }
  
  @HttpMethod
  public void deleteEmployee(
      @UriParam("id") int id) {
    ...
  }
}

Other request information can also be consumed by using method arguments. For example, note the use of the UriParam annotation in the example above. Before a method is invoked, the employee ID is extracted from request URI automatically and cast to the Java primitive type int. If the employee ID cannot be cast, then the runtime returns a 400 Bad Request. So in this example, the client is restricting employee IDs in the URI to strings that contain only digits. The same technique can be used for URI query parameters by use of the QueryParam annotation.

The following types may be annotated with a UriParam, QueryParam, HeaderParam or a MatrixParam annotation: all primitive types (except char), primitive wrapper classes (except Character), String, any class that has a static method with the signature valueOf(String), and any class that has a constructor that takes a String parameter. In addition, the QueryParam annotation supports List<T>, where T is a supported type as previously stated, for the case where multiple values for a query parameter are present.

It is possible to specify at the level of a Java method what MIME media types are consumed and produced. For example, the Employees class may be extended to support additional formats with the following additional methods:

  @HttpMethod
  @ProduceMime("text/xhtml")
  public DataSource getEmployeeListAsHTML() {
      ...
  }
    
  @HttpMethod
  @ConsumeMime("application/x-www-form-urlencoded")
  public Employee postEmployeeFromForm(
      FormURLEncodedProperties employee) {
    ...
  }

If a client sends an HTTP GET request to the employees URI stating that the MIME media type text/xhtml is preferable over application/employee+xml, then the getEmployeeListAsHTML method is invoked (instead of the getEmployee method) and returns a representation of the employees as an XHTML document. If a client sends an HTTP POST request with a HTTP request entity that was produced from an HTML form, then the createEmployeeFromForm method is invoked (instead of the createEmployee method).

NOTE: A client declares what MIME media types are preferable using the Accept HTTP request header field. In the above example, the HTTP request may, for example, include Accept: text/html;q=1.0, application/employees+xml;q=0.6 to indicate that text/html is preferable over application/employees+xml.

An application can also return a specific HTTP response. Below is an expanded version of the Employees class that uses the HTTP 201 Created status to indicate that a new resource has been created.

@UriTemplate("/employees")
@ConsumeMime("application/employee+xml")
@ProduceMime("application/employee+xml")
public class Employees {

  @HttpMethod
  public Created postEmployee(
      Employee employee) {
    Employee newEmployee = addEmployee(employee);
    return new Created(new Representation(newEmployee),  newEmployee.getUri());
  }
}

What Status Codes Could Be Returned?

The runtime manages the returning of status codes for many common errors cases. If a client sends an HTTP POST request to the employee resource, the runtime returns a 405 Method Not Allowed response. If a client sends an HTTP PUT request to the employee resource where the media type of the request entity is anything other than application/employee+xml, then the runtime returns a 415 Unsupported Media Type response.

Error conditions can be signalled using an exception, for example, the following code can be used to inform the client that an employee resource has gone.

@HttpMethod("GET")
public Representation<Employee> getEmployee(
    @UriParam("id") int id) {
  if (!doesEmployeeExist(id)) {
    throw new WebApplicationException(410);
  }
  ...
}

Deploying a RESTful Web Service

The first step in deploying a RESTful Web Service is to compile your Java classes with APT. When you compile your resources with APT, the Annotation Processor is run, which generates some handy artifacts that make deploying your application easier. One of the artifacts generated is a WebResources class. This class is used by the runtime to load your resources into the application. The annotation processor can also generate a web.xml file that can be used to deploy into a servlet container, a application.wadl file, which is a WADL description of your resources, and a WadlResource class that can be used to access the WADL description.

APT can be invoked through an APT ant task supplied with this release.

For APT to find the annotation processor, make sure that the jersey.jar is on the classpath passed to APT.

The annotation processor can accept the following options:

Option

Description

Command-Line Example

Default Value

urlpattern

Specify the url-pattern to be placed in the generated web.xml.

-Aurlpattern=/myapp/*

/resources/*

servletname

Specify the servlet-name to be placed in the generated web.xml.

-Aservletname="My APP"

Web Application

webresourcespkg

Specify the package to generate the WebResources class into.

-Awebresourcespkg=com.sun.rest.sample

webresources

noservlet

Turn off the generation of web.xml.

-Anoservlet

web.xml is generated.

nowadl

Turn off the generation of the application.wadl and the WadlResource class.

-Anowadl

application.wadl and WadlResource class are generated.

webresourcesdestdir

Specify the destination directory for the generated /WEB-INF/web.xml relative to APT's destination directory.

-Awebresourcesdestdir=../..

APT destination directory

All of the examples utilize the APT ant task, so you can refer to them for concrete examples of how to invoke APT

The following is taken from the SimpleServlet example. For the APT ant task to run, it must have the jersey.jar and the tools.jar from Java SE 5 or higher. To execute the APT ant task in Java SE 6 requires that the xEnsorsed="true" be set on the task. (Note that if there is a runtime dependency on JAXB 2.1 or JAX-WS 2.1 jars then these jars must be placed in the endorsed directory of the Java SE 6 distribution, or by setting the endorsed directory using the system property "java.endorsed.dirs".)

Notice that the options are specified using the <option> element.

<taskdef name="rbpt" classname="com.sun.ws.rest.tools.ant.WebResourcesProcessorTask">
    <classpath location="${file.reference.jersey.jar}"/>
</taskdef>

<target name="-pre-compile">
    <echo message="Processing resource classes"/>
    <rbpt fork="true" debug="true" verbose="false" xEndorsed="true"
	 nocompile="false"
	 destdir="${build.classes.dir.real}"
	 sourcedestdir="gen-src"  
	 sourcePath="${src.dir}">
	<classpath>
	    <path path="${javac.classpath}"/>
	    <pathelement location="${build.web.dir}/WEB-INF/classes"/>
	</classpath>
	<option key="webresourcesdestdir" value="../.."/>
	<option key="webresourcespkg" value="com.sun.ws.rest.samples.servlet.resources"/>
	<option key="noservlet"/>
	<source dir="${src.dir}">
	    <include name="**/*.java"/>
	</source>
    </rbpt>    
    <copy todir="${build.classes.dir}">
	<fileset dir="${src.dir}" excludes="**/*.java"/>
    </copy>
</target>

Java EE Servlet Container

To deploy to a Java EE servlet container, you must make sure that the jersey.jar and all of the other jars upon which it is dependent are in the servlet container's classpath. This can be done by either copying the jar files to one of the servlet container's library directories, or by simply WARing the jar files into the application WAR file. The application WAR file should contain your Java classes, the generated WebResources class, and the generated WEB-INF/web.xml file. This WAR file can then be deployed to your servlet container.

The following shows the WEB-INF/web.xml file generated for the SimpleServlet example. The web.xml specifies the com.sun.ws.rest.impl.container.servlet.ServletAdaptor as the <servlet-class>. This adapter uses the resourcebean <init-param> to get the set of Java classes to include in the application.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <servlet>
    <servlet-name>Web Application</servlet-name>
    <servlet-class>com.sun.ws.rest.impl.container.servlet.ServletAdaptor</servlet-class>
    <init-param>
      <param-name>resourcebean</param-name>
      <param-value>com.sun.ws.rest.samples.servlet.resources.WebResources</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Web Application</servlet-name>
    <url-pattern>/resources/*</url-pattern>
  </servlet-mapping>
</web-app>

The following shows the contents of the SimpleServlet sample WAR file.

META-INF/context.xml
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/MasterResourceBean.class
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/WebResources.class
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/ResourceBean1.class
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/ResourceBean2.class
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/ResourceBean3.class
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/ResourceBean4.class
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/index.html
WEB-INF/classes/com/sun/ws/rest/samples/servlet/resources/java.jpg
WEB-INF/classes/com/sun/ws/rest/wadl/resource/WadlResource.class
WEB-INF/classes/com/sun/ws/rest/wadl/resource/application.wadl
WEB-INF/lib/activation.jar
WEB-INF/lib/jaxb-api.jar
WEB-INF/lib/jaxb-impl.jar
WEB-INF/lib/jaxws-api.jar
WEB-INF/lib/jdom-1.0.jar
WEB-INF/lib/jersey.jar
WEB-INF/lib/jsr173_api.jar
WEB-INF/lib/jsr250-api.jar
WEB-INF/lib/jsr311-api.jar
WEB-INF/lib/localizer.jar
WEB-INF/lib/mail.jar
WEB-INF/lib/persistence-api-1.0.jar
WEB-INF/lib/rome-0.9.jar
WEB-INF/web.xml
index.html

JAX-WS Endpoint Container

When deploying to a JAX-WS Endpoint container, you do not need the generated WEB-INF/web.xml, because a servlet container is not used. To prevent the generation of this file, you can use the noservlet option for APT. The following is taken from the SimpleJAXWSEndpoint example. It shows how the APT ant task is used with this option.

<target name="-pre-compile">
    <echo message="Processing resource classes"/>
    <rbpt fork="true" destdir="${build.classes.dir}" xEndorsed="true"
	 sourcedestdir="gen-src" sourcePath="${src.dir}">
	<classpath>
	    <path path="${javac.classpath}"/>
	    <pathelement location="${build.dir}"/>
	</classpath>                 
	<option key="webresourcesdestdir" value="."/>
	<option key="webresourcespkg" value="com.sun.ws.rest.samples.jaxws.resources"/>
        <option key="noservlet"/>
	<source dir="${src.dir}">
	    <include name="**/*.java"/>
	</source>
    </rbpt>    
    <copy todir="${build.classes.dir}">
	<fileset dir="${src.dir}" excludes="**/*.java"/>
    </copy>
</target>

To deploy to a JAX-WS endpoint, you must write a simple Main class that can be used to publish the endpoint. The following is the Main class taken from the SimpleJAXWSEndpoint example.

import com.sun.jersey.api.container.ContainerFactory;
import javax.xml.ws.Endpoint;
import javax.xml.ws.Provider;
import javax.xml.ws.http.HTTPBinding;

public class Main {
    
    /** Creates a new instance of Main */
    public Main() {
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        /** Create a JAX-WS Provider */
        Provider provider = ContainerFactory.createContainer(Provider.class,
                "com.sun.ws.rest.samples.jaxws.resources");
        
        /** Create a JAX-WS Endpoint with the provider */
        Endpoint endpoint = Endpoint.create(HTTPBinding.HTTP_BINDING,provider);
        /** publish the endpoint */
        endpoint.publish("http://localhost:9998/endpoint");
        
        System.out.println("JAX-WS endpoint running, visit: http://127.0.0.1:9998/endpoint/start, hit return to stop...");
        /** wait of for a CR */
        System.in.read();
        System.out.println("Stopping JAX-WS endpoint");
        
        /* stop the endpoint */
        endpoint.stop();
        System.out.println("Server stopped");        
    }
    
}

The following line uses the ProviderFactory to create a JAX-WS Provider:

Provider provider = ContainerFactory.createContainer(Provider.class,
                "com.sun.ws.rest.samples.jaxws.resources");

The ContainerFactory.createContainer method takes two parameters, the type of container which to create, and package name that contains the WebResources class. An alternative create is also available that can be passed a ResourceConfig should you wish to avoid the apt step.

The following line creates a JAX-WS Endpoint:

Endpoint endpoint = Endpoint.create(HTTPBinding.HTTP_BINDING,provider);

It is passed the HTTPBinding.HTTP_BINDING, which specifies that the XML/HTTP binding should be used and the provider created in the previous line.

The following line does the actual publishing of the endpoint:

endpoint.publish("http://localhost:9998/endpoint");

It takes one argument, which is the URL at which the endpoint should be published.

The following line is simply there to wait for the user to press the Return key:

System.in.read();

... before stopping the endpoint with the following line:

endpoint.stop();

When running a JAX-WS Endpoint-based application, the the API, runtime and dependent jar files, the JAX-WS runtime jar files, the generated WebResources, and your Java classes must all be in the classpath.

Lightweight HTTP Server Container

The SimpleConsole example application shows how to use the API with the lightweight HTTP server. Note in particular the -pre-compile target in the build.xml file that generates the classes (primarily WebResources) (as described above). Note also the use of the noservlet option to prevent generation of a web.xml file as in the previous example.

Samples

The distribution contains the following examples that utilize the features of the RESTful API (some of which have been described in this document):

Contacts

In the process of designing and implementing the API, the development team has identified a number of enhancements, planned for future versions of the API, that will improve ease of use and provide new features. In the meantime, we hope that developers will play with the API, build example programs and provide feedback that we may incorporate in future versions. Additional information can be found on the following team members weblogs:

Paul Sandoz
http://blogs.sun.com/sandoz/
Marc Hadley
http://weblogs.java.net/blog/mhadley