JAX-RS

3. JAX-RS Application, Resources and Sub-Resources

Table of Contents

3.1. Root Resource Classes
3.1.1. @Path
3.1.2. @GET, @PUT, @POST, @DELETE, ... (HTTP Methods)
3.1.3. @Produces
3.1.4. @Consumes
3.2. Parameter Annotations (@*Param)
3.3. Sub-resources
3.4. Life-cycle of Root Resource Classes
3.5. Rules of Injection
3.6. Use of @Context

This chapter presents an overview of the core JAX-RS concepts - resources and sub-resources.

The JAX-RS 2.0-SNAPSHOT JavaDoc can be found online here.

The JAX-RS 2.0-SNAPSHOT specification draft can be found online here.

3.1. Root Resource Classes

Root resource classes are POJOs (Plain Old Java Objects) that are annotated with @Path have at least one method annotated with @Path or a resource method designator annotation such as @GET, @PUT, @POST, @DELETE. Resource methods are methods of a resource class annotated with a resource method designator. This section shows how to use Jersey to annotate Java objects to create RESTful web services.

The following code example is a very simple example of a root resource class using JAX-RS annotations. The example code shown here is from one of the samples that ships with Jersey, the zip file of which can be found in the maven repository here.


Example 3.1. Simple hello world root resource class

package org.glassfish.jersey.examples.helloworld;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
 
@Path("helloworld")
public class HelloWorldResource {
    public static final String CLICHED_MESSAGE = "Hello World!";
 
    @GET
    @Produces("text/plain")
    public String getHello() {
        return CLICHED_MESSAGE;
    }
}


Let's look at some of the JAX-RS annotations used in this example.

3.1.1. @Path

The @Path annotation's value is a relative URI path. In the example above, the Java class will be hosted at the URI path /helloworld. This is an extremely simple use of the @Path annotation. What makes JAX-RS so useful is that you can embed variables in the URIs.

URI path templates are URIs with variables embedded within the URI syntax. These variables are substituted at runtime in order for a resource to respond to a request based on the substituted URI. Variables are denoted by curly braces. For example, look at the following @Path annotation:

@Path("/users/{username}")

In this type of example, a user will be prompted to enter their name, and then a Jersey web service configured to respond to requests to this URI path template will respond. For example, if the user entered their username as "Galileo", the web service will respond to the following URL: http://example.com/users/Galileo

To obtain the value of the username variable the @PathParam may be used on method parameter of a request method, for example:

Example 3.2. Specifying URI path parameter

 @Path("/users/{username}") public class UserResource {
 
    @GET
    @Produces("text/xml")
    public String getUser(@PathParam("username") String userName) {
        ...
    }
}


If it is required that a user name must only consist of lower and upper case numeric characters then it is possible to declare a particular regular expression, which overrides the default regular expression, "[^/]+?", for example:

1 @Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")

In this type of example the username variable will only match user names that begin with one upper or lower case letter and zero or more alpha numeric characters and the underscore character. If a user name does not match that a 404 (Not Found) response will occur.

A @Path value may or may not begin with a '/', it makes no difference. Likewise, by default, a @Path value may or may not end in a '/', it makes no difference, and thus request URLs that end or do not end in a '/' will both be matched.

3.1.2. @GET, @PUT, @POST, @DELETE, ... (HTTP Methods)

@GET, @PUT, @POST, @DELETE and @HEAD are resource method designator annotations defined by JAX-RS and which correspond to the similarly named HTTP methods. In the example above, the annotated Java method will process HTTP GET requests. The behavior of a resource is determined by which of the HTTP methods the resource is responding to.

The following example is an extract from the storage service sample that shows the use of the PUT method to create or update a storage container:

Example 3.3. PUT method

 @PUT
public Response putContainer() {
    System.out.println("PUT CONTAINER " + container);
 
    URI uri =  uriInfo.getAbsolutePath();
    Container c = new Container(container, uri.toString());
 
    Response r;
    if (!MemoryStore.MS.hasContainer(c)) {
        r = Response.created(uri).build();
    } else {
        r = Response.noContent().build();
    }
 
    MemoryStore.MS.createContainer(c);
    return r;
}


By default the JAX-RS runtime will automatically support the methods HEAD and OPTIONS, if not explicitly implemented. For HEAD the runtime will invoke the implemented GET method (if present) and ignore the response entity (if set). For OPTIONS the Allow response header will be set to the set of HTTP methods support by the resource. In addition Jersey will return a WADL document describing the resource.

3.1.3. @Produces

The @Produces annotation is used to specify the MIME media types of representations a resource can produce and send back to the client. In this example, the Java method will produce representations identified by the MIME media type "text/plain". @Produces can be applied at both the class and method levels. Here's an example:

Example 3.4. Specifying output MIME type

@Path("/myResource")
@Produces("text/plain")
public class SomeResource {
    @GET
    public String doGetAsPlainText() {
        ...
    }
 
    @GET
    @Produces("text/html")
    public String doGetAsHtml() {
        ...
    }
}


The doGetAsPlainText method defaults to the MIME type of the @Produces annotation at the class level. The doGetAsHtml method's @Produces annotation overrides the class-level @Produces setting, and specifies that the method can produce HTML rather than plain text.

If a resource class is capable of producing more that one MIME media type then the resource method chosen will correspond to the most acceptable media type as declared by the client. More specifically the Accept header of the HTTP request declared what is most acceptable. For example if the Accept header is "Accept: text/plain" then the doGetAsPlainText method will be invoked. Alternatively if the Accept header is "Accept: text/plain;q=0.9, text/html", which declares that the client can accept media types of "text/plain" and "text/html" but prefers the latter, then the doGetAsHtml method will be invoked.

More than one media type may be declared in the same @Produces declaration, for example:

Example 3.5. Using multiple output MIME types

 @GET
@Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
    ...
}


The doGetAsXmlOrJson method will get invoked if either of the media types "application/xml" and "application/json" are acceptable. If both are equally acceptable then the former will be chosen because it occurs first.

Optionally, server can also specify the quality factor for individual media types. These are considered if several are equally acceptable by the client. For example:

Example 3.6. Server-side content negotiation

 @GET
@Produces({"application/xml; qs=0.9", "application/json"})
public String doGetAsXmlOrJson() {
    ...
}


In the above sample, if client accepts both "application/xml" and "application/json" (equally), then server always sends "application/json", since "application/xml" has a lower quality factor.

The examples above refer explicitly to MIME media types for clarity. It is possible to refer to constant values, which may reduce typographical errors, see the constant field values of MediaType.

3.1.4. @Consumes

The @Consumes annotation is used to specify the MIME media types of representations a resource can consume that were sent by the client. The above example can be modified to set the cliched message as follows:

Example 3.7. Specifying input MIME type

 @POST
@Consumes("text/plain")
public void postClichedMessage(String message) {
    // Store the message
}




In this example, the Java method will consume representations identified by the MIME media type "text/plain". Notice that the resource method returns void. This means no representation is returned and response with a status code of 204 (No Content) will be returned.

@Consumes can be applied at both the class and the method levels and more than one media type may be declared in the same @Consumes declaration.

3.2. Parameter Annotations (@*Param)

Parameters of a resource method may be annotated with parameter-based annotations to extract information from a request. One of the previous examples presented the use of @PathParam to extract a path parameter from the path component of the request URL that matched the path declared in @Path.

@QueryParam is used to extract query parameters from the Query component of the request URL. The following example is an extract from the sparklines sample:

Example 3.8. Query parameters

 @Path("smooth")
@GET
public Response smooth(
        @DefaultValue("2") @QueryParam("step") int step,
        @DefaultValue("true") @QueryParam("min-m") boolean hasMin,
        @DefaultValue("true") @QueryParam("max-m") boolean hasMax,
        @DefaultValue("true") @QueryParam("last-m") boolean hasLast,
        @DefaultValue("blue") @QueryParam("min-color") ColorParam minColor,
        @DefaultValue("green") @QueryParam("max-color") ColorParam maxColor,
        @DefaultValue("red") @QueryParam("last-color") ColorParam lastColor
        ) { ... }



If a query parameter "step" exists in the query component of the request URI then the "step" value will be will extracted and parsed as a 32 bit signed integer and assigned to the step method parameter. If "step" does not exist then a default value of 2, as declared in the @DefaultValue annotation, will be assigned to the step method parameter. If the "step" value cannot be parsed as a 32 bit signed integer then a HTTP 404 (Not Found) response is returned. User defined Java types such as ColorParam may be used, which as implemented as follows:

Example 3.9. Custom Java type for consuming request parameters

 public class ColorParam extends Color {
    public ColorParam(String s) {
        super(getRGB(s));
    }
 
    private static int getRGB(String s) {
        if (s.charAt(0) == '#') {
            try {
                Color c = Color.decode("0x" + s.substring(1));
                return c.getRGB();
            } catch (NumberFormatException e) {
                throw new WebApplicationException(400);
            }
        } else {
            try {
                Field f = Color.class.getField(s);
                return ((Color)f.get(null)).getRGB();
            } catch (Exception e) {
                throw new WebApplicationException(400);
            }
        }
    }
}



In general the Java type of the method parameter may:

Be a primitive type;

Have a constructor that accepts a single String argument;

Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String) and java.util.UUID.fromString(String)); or

Be List, Set or SortedSet, where T satisfies 2 or 3 above. The resulting collection is read-only.

Sometimes parameters may contain more than one value for the same name. If this is the case then types in 4) may be used to obtain all values.

If the @DefaultValue is not used in conjunction with @QueryParam and the query parameter is not present in the request then value will be an empty collection for List, Set or SortedSet, null for other object types, and the Java-defined default for primitive types.

The @PathParam and the other parameter-based annotations, @MatrixParam, @HeaderParam, @CookieParam, @FormParam obey the same rules as @QueryParam. @MatrixParam extracts information from URL path segments. @HeaderParam extracts information from the HTTP headers. @CookieParam extracts information from the cookies declared in cookie related HTTP headers.

@FormParam is slightly special because it extracts information from a request representation that is of the MIME media type "application/x-www-form-urlencoded" and conforms to the encoding specified by HTML forms, as described here. This parameter is very useful for extracting information that is POSTed by HTML forms, for example the following extracts the form parameter named "name" from the POSTed form data:

Example 3.10. Processing POSTed HTML form
 

 @POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("name") String name) {
    // Store the message
}




If it is necessary to obtain a general map of parameter name to values then, for query and path parameters it is possible to do the following:

Example 3.11. Obtaining general map of URI path and/or query parameters

@GET
public String get(@Context UriInfo ui) {
    MultivaluedMap queryParams = ui.getQueryParameters();
    MultivaluedMap pathParams = ui.getPathParameters();
}




For header and cookie parameters the following:

Example 3.12. Obtaining general map of header parameters

 @GET
public String get(@Context HttpHeaders hh) {
    MultivaluedMap headerParams = hh.getRequestHeaders();
    Map pathParams = hh.getCookies();
}




In general @Context can be used to obtain contextual Java types related to the request or response.

Because form parameters (unlike others) are part of the message entity, it is possible to do the following:

Example 3.13. Obtaining general map of form parameters

@POST
@Consumes("application/x-www-form-urlencoded")
public void post(MultivaluedMap formParams) {
    // Store the message
}


I.e. you don't need to use the @Context annotation.

Another kind of injection is the @BeanParam which allows to inject the parameters described above into a single bean. A bean annotated with @BeanParam containing any fields and appropriate *param annotation(like @PathParam) will be initialized with corresponding request values in expected way as if these fields were in the resource class. Then instead of injecting request values like path param in constructor parameters or class fields the @BeanParam can be used to inject such a bean into a resource or resource method. The @BeanParam is used this way to aggregate more request parameters into a single bean.

Example 3.14. Example of the bean which will be used as @BeanParam

 public class MyBeanParam {
    @PathParam("p")
    private String pathParam;
 
    @MatrixParam("m")
    @Encoded
    @DefaultValue("default")
    private String matrixParam;
 
    @HeaderParam("header")
    private String headerParam;
 
    private String queryParam;
 
    public MyBeanParam(@QueryParam("q") String queryParam) {
        this.queryParam = queryParam;
    }
 
    public String getPathParam() {
    return pathParam;
    }
    ...
}



Example 3.15. Injection of MyBeanParam as a method parameter:

 @POST
public void post(@BeanParam MyBeanParam beanParam, String entity) {
    final String pathParam = beanParam.getPathParam(); // contains injected path parameter "p"
    ...
}



The example shows aggregation of injections @PathParam, @QueryParam @MatrixParam and @HeaderParam into one signle bean. The rules for injections inside the bean are the same as described above for these injections. The @DefaultValue is used to define the default value for matrix parameter matrixParam. Also the @Encoded annotation has the same behaviour as if it were used for injection in the resource method directly. Injecting the bean parameter into @Singleton resource class fields is not allowed (injections into method parameter must be used instead).

@BeanParam can contain all parameters injections injections (@PathParam, @QueryParam, @MatrixParam, @HeaderParam, @CookieParam, @FormParam).More beans can be injected into one resource or method parameters even if they inject the same request values. For example the following is possible:

Example 3.16. Injection of more beans into one resource methods:

 @POST
public void post(@BeanParam MyBeanParam beanParam, @BeanParam AnotherBean anotherBean, @PathParam("p") pathParam,
String entity) {
    // beanParam.getPathParam() == pathParam
    ...
}



3.3. Sub-resources


@Path may be used on classes and such classes are referred to as root resource classes. @Path may also be used on methods of root resource classes. This enables common functionality for a number of resources to be grouped together and potentially reused.

The first way @Path may be used is on resource methods and such methods are referred to as sub-resource methods. The following example shows the method signatures for a root resource class from the jmaki-backend sample:

Example 3.17. Sub-resource methods

@Singleton
@Path("/printers")
public class PrintersResource {
 
    @GET
    @Produces({"application/json", "application/xml"})
    public WebResourceList getMyResources() { ... }
 
    @GET @Path("/list")
    @Produces({"application/json", "application/xml"})
    public WebResourceList getListOfPrinters() { ... }
 
    @GET @Path("/jMakiTable")
    @Produces("application/json")
    public PrinterTableModel getTable() { ... }
 
    @GET @Path("/jMakiTree")
    @Produces("application/json")
    public TreeModel getTree() { ... }
 
    @GET @Path("/ids/{printerid}")
    @Produces({"application/json", "application/xml"})
    public Printer getPrinter(@PathParam("printerid") String printerId) { ... }
 
    @PUT @Path("/ids/{printerid}")
    @Consumes({"application/json", "application/xml"})
    public void putPrinter(@PathParam("printerid") String printerId,  Printer printer) { ... }
 
    @DELETE @Path("/ids/{printerid}")
    public void deletePrinter(@PathParam("printerid") String printerId) { ... }
}




If the path of the request URL is "printers" then the resource methods not annotated with @Path will be selected. If the request path of the request URL is "printers/list" then first the root resource class will be matched and then the sub-resource methods that match "list" will be selected, which in this case is the sub-resource method getListOfPrinters. So in this example hierarchical matching on the path of the request URL is performed.

The second way @Path may be used is on methods not annotated with resource method designators such as @GET or @POST. Such methods are referred to as sub-resource locators. The following example shows the method signatures for a root resource class and a resource class from the optimistic-concurrency sample:

Example 3.18. Sub-resource locators

@Path("/item")
public class ItemResource {
    @Context UriInfo uriInfo;
 
    @Path("content")
    public ItemContentResource getItemContentResource() {
        return new ItemContentResource();
    }
 
    @GET
    @Produces("application/xml")
    public Item get() { ... }
}
 
public class ItemContentResource {
 
    @GET
    public Response get() { ... }
 
    @PUT
    @Path("{version}")
    public void put(
            @PathParam("version") int version,
            @Context HttpHeaders headers,
            byte[] in) { ... }
}




The root resource class ItemResource contains the sub-resource locator method getItemContentResource that returns a new resource class. If the path of the request URL is "item/content" then first of all the root resource will be matched, then the sub-resource locator will be matched and invoked, which returns an instance of the ItemContentResource resource class. Sub-resource locators enable reuse of resource classes.

In addition the processing of resource classes returned by sub-resource locators is performed at runtime thus it is possible to support polymorphism. A sub-resource locator may return different sub-types depending on the request (for example a sub-resource locator could return different sub-types dependent on the role of the principle that is authenticated).

Note that the runtime will not manage the life-cycle or perform any field injection onto instances returned from sub-resource locator methods. This is because the runtime does not know what the life-cycle of the instance is.

3.4. Life-cycle of Root Resource Classes

By default the life-cycle of root resource classes is per-request, namely that a new instance of a root resource class is created every time the request URI path matches the root resource. This makes for a very natural programming model where constructors and fields can be utilized (as in the previous section showing the constructor of the SparklinesResource class) without concern for multiple concurrent requests to the same resource.

In general this is unlikely to be a cause of performance issues. Class construction and garbage collection of JVMs has vastly improved over the years and many objects will be created and discarded to serve and process the HTTP request and return the HTTP response.

Instances of singleton root resource classes can be declared by an instance of Application.

Jersey supports two further life-cycles using Jersey specific annotations. If a root resource class is annotated with @Singleton then only one instance is created per-web application. If a root resource class is annotated with @PerSession then one instance is created per web session and stored as a session attribute.

3.5. Rules of Injection

Previous sections have presented examples of annotated types, mostly annotated method parameters but also annotated fields of a class, for the injection of values onto those types.

This section presents the rules of injection of values on annotated types. Injection can be performed on fields, constructor parameters, resource/sub-resource/sub-resource locator method parameters and bean setter methods. The following presents an example of all such injection cases:

Example 3.19. Injection

@Path("id: \d+")
public class InjectedResource {
    // Injection onto field
    @DefaultValue("q") @QueryParam("p")
    private String p;
 
    // Injection onto constructor parameter
    public InjectedResource(@PathParam("id") int id) { ... }
 
    // Injection onto resource method parameter
    @GET
    public String get(@Context UriInfo ui) { ... }
 
    // Injection onto sub-resource resource method parameter
    @Path("sub-id")
    @GET
    public String get(@PathParam("sub-id") String id) { ... }
 
    // Injection onto sub-resource locator method parameter
    @Path("sub-id")
    public SubResource getSubResource(@PathParam("sub-id") String id) { ... }
 
    // Injection using bean setter method
    @HeaderParam("X-header")
    public void setHeader(String header) { ... }
}




There are some restrictions when injecting on to resource classes with a life-cycle other than per-request. In such cases it is not possible to injected onto fields for the annotations associated with extraction of request parameters. However, it is possible to use the @Context annotation on fields, in such cases a thread local proxy will be injected.

The @FormParam annotation is special and may only be utilized on resource and sub-resource methods. This is because it extracts information from a request entity.

3.6. Use of @Context

Previous sections have introduced the use of @Context. Chapter 5 of the JAX-RS specification presents all the standard JAX-RS Java types that may be used with @Context.

When deploying a JAX-RS application using servlet then ServletConfig, ServletContext, HttpServletRequest and HttpServletResponse are available using @Context.

Chapter 4. Representations and Responses

Table of Contents

4.1. Representations and Java Types
4.2. Building Responses
4.3. WebApplicationException and Mapping Exceptions to Responses
4.4. Conditional GETs and Returning 304 (Not Modified) Responses

4.1. Representations and Java Types

Previous sections on @Produces and @Consumes referred to MIME media types of representations and showed resource methods that consume and produce the Java type String for a number of different media types. However, String is just one of many Java types that are required to be supported by JAX-RS implementations.

Java types such as byte[], java.io.InputStream, java.io.Reader and java.io.File are supported. In addition JAXB beans are supported. Such beans are JAXBElement or classes annotated with @XmlRootElement or @XmlType. The samples jaxb and json-from-jaxb show the use of JAXB beans.

Unlike method parameters that are associated with the extraction of request parameters, the method parameter associated with the representation being consumed does not require annotating. A maximum of one such unannotated method parameter may exist since there may only be a maximum of one such representation sent in a request.

The representation being produced corresponds to what is returned by the resource method. For example JAX-RS makes it simple to produce images that are instance of File as follows:

Example 4.1. Using File with a specific MIME type to produce a response

@GET
@Path("/images/{image}")
@Produces("image/*")
public Response getImage(@PathParam("image") String image) {
    File f = new File(image);
 
    if (!f.exists()) {
        throw new WebApplicationException(404);
    }
 
    String mt = new MimetypesFileTypeMap().getContentType(f);
    return Response.ok(f, mt).build();
}

A File type can also be used when consuming, a temporary file will be created where the request entity is stored.

The Content-Type (if not set, see next section) can be automatically set from the MIME media types declared by @Produces if the most acceptable media type is not a wild card (one that contains a *, for example "application/" or "/*"). Given the following method, the most acceptable MIME type is used when multiple output MIME types allowed:

@GET
@Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
    ...
}

If "application/xml" is the most acceptable then the Content-Type of the response will be set to "application/xml".

4.2. Building Responses

Sometimes it is necessary to return additional information in response to a HTTP request. Such information may be built and returned using Response and Response.ResponseBuilder. For example, a common RESTful pattern for the creation of a new resource is to support a POST request that returns a 201 (Created) status code and a Location header whose value is the URI to the newly created resource. This may be achieved as follows:

Example 4.2. Returning 201 status code and adding Location header in response to POST request

@POST
@Consumes("application/xml")
public Response post(String content) {
    URI createdUri = ...
    create(content);
    return Response.created(createdUri).build();
}




In the above no representation produced is returned, this can be achieved by building an entity as part of the response as follows:

Example 4.3. Adding an entity body to a custom response

@POST
@Consumes("application/xml")
public Response post(String content) {
    URI createdUri = ...
    String createdContent = create(content);
    return Response.created(createdUri).entity(createdContent).build();
}

Response building provides other functionality such as setting the entity tag and last modified date of the representation.

4.3. WebApplicationException and Mapping Exceptions to Responses

Previous sections have shown how to return HTTP responses and it is possible to return HTTP errors using the same mechanism. However, sometimes when programming in Java it is more natural to use exceptions for HTTP errors.

The following example shows the throwing of a NotFoundException from the bookmark sample:

Example 4.4. Throwing Jersey specific exceptions to control response

@Path("items/{itemid}/")
public Item getItem(@PathParam("itemid") String itemid) {
    Item i = getItems().get(itemid);
    if (i == null)
        throw new NotFoundException("Item, " + itemid + ", is not found");
 
    return i;
}


This exception is a Jersey specific exception that extends WebApplicationException and builds a HTTP response with the 404 status code and an optional message as the body of the response:

Example 4.5. Jersey specific exception implementation

 public class NotFoundException extends WebApplicationException {
 
    /**
     * Create a HTTP 404 (Not Found) exception.
     */
    public NotFoundException() {
        super(Responses.notFound().build());
    }
 
    /**
     * Create a HTTP 404 (Not Found) exception.
     * @param message the String that is the entity of the 404 response.
     */
    public NotFoundException(String message) {
        super(Response.status(Responses.NOT_FOUND).
                entity(message).type("text/plain").build());
    }
 
}

In other cases it may not be appropriate to throw instances of WebApplicationException, or classes that extend WebApplicationException, and instead it may be preferable to map an existing exception to a response. For such cases it is possible to use the ExceptionMapper interface. For example, the following maps the EntityNotFoundException to a HTTP 404 (Not Found) response:

Example 4.6. Mapping generic exceptions to responses

@Provider
public class EntityNotFoundMapper implements
        ExceptionMapper {
    public Response toResponse(javax.persistence.EntityNotFoundException ex) {
        return Response.status(404).
            entity(ex.getMessage()).
            type("text/plain").
            build();
    }
}


The above class is annotated with @Provider, this declares that the class is of interest to the JAX-RS runtime. Such a class may be added to the set of classes of the Application instance that is configured. When an application throws an EntityNotFoundException the toResponse method of the EntityNotFoundMapper instance will be invoked.

4.4. Conditional GETs and Returning 304 (Not Modified) Responses

Conditional GETs are a great way to reduce bandwidth, and potentially server-side performance, depending on how the information used to determine conditions is calculated. A well-designed web site may return 304 (Not Modified) responses for the many of the static images it serves.

JAX-RS provides support for conditional GETs using the contextual interface Request.

The following example shows conditional GET support from the sparklines sample:

Example 4.7. Conditional GET support

public SparklinesResource(
        @QueryParam("d") IntegerList data,
        @DefaultValue("0,100") @QueryParam("limits") Interval limits,
        @Context Request request,
        @Context UriInfo ui) {
    if (data == null)
        throw new WebApplicationException(400);
 
    this.data = data;
 
    this.limits = limits;
 
    if (!limits.contains(data))
        throw new WebApplicationException(400);
 
    this.tag = computeEntityTag(ui.getRequestUri());
    if (request.getMethod().equals("GET")) {
        Response.ResponseBuilder rb = request.evaluatePreconditions(tag);
        if (rb != null)
            throw new WebApplicationException(rb.build());
    }
}

The constructor of the SparklinesResouce root resource class computes an entity tag from the request URI and then calls the request.evaluatePreconditions with that entity tag. If a client request contains an If-None-Match header with a value that contains the same entity tag that was calculated then the evaluatePreconditions returns a pre-filled out response, with the 304 status code and entity tag set, that may be built and returned. Otherwise, evaluatePreconditions returns null and the normal response can be returned.

Notice that in this example the constructor of a resource class can be used perform actions that may otherwise have to be duplicated to invoked for each resource method.

 Chapter 5. URIs and Links

Table of Contents

5.1. Building URIs

 
5.1. Building URIs

A very important aspects of REST is hyperlinks, URIs, in representations that clients can use to transition the Web service to new application states (this is otherwise known as "hypermedia as the engine of application state"). HTML forms present a good example of this in practice.

Building URIs and building them safely is not easy with java.net.URI, which is why JAX-RS has the UriBuilder class that makes it simple and easy to build URIs safely.

UriBuilder can be used to build new URIs or build from existing URIs. For resource classes it is more than likely that URIs will be built from the base URI the web service is deployed at or from the request URI. The class UriInfo provides such information (in addition to further information, see next section).

The following example shows URI building with UriInfo and UriBuilder from the bookmark sample:

Example 5.1. URI building

@Path("/users/")
public class UsersResource {
 
    @Context UriInfo uriInfo;
 
    ...
 
    @GET
    @Produces("application/json")
    public JSONArray getUsersAsJsonArray() {
        JSONArray uriArray = new JSONArray();
        for (UserEntity userEntity : getUsers()) {
            UriBuilder ub = uriInfo.getAbsolutePathBuilder();
            URI userUri = ub.
                    path(userEntity.getUserid()).
                    build();
            uriArray.put(userUri.toASCIIString());
        }
        return uriArray;
    }
}




UriInfo is obtained using the @Context annotation, and in this particular example injection onto the field of the root resource class is performed, previous examples showed the use of @Context on resource method parameters.

UriInfo can be used to obtain URIs and associated UriBuilder instances for the following URIs: the base URI the application is deployed at; the request URI; and the absolute path URI, which is the request URI minus any query components.

The getUsersAsJsonArray method constructs a JSONArrray where each element is a URI identifying a specific user resource. The URI is built from the absolute path of the request URI by calling UriInfo.getAbsolutePathBuilder(). A new path segment is added, which is the user ID, and then the URI is built. Notice that it is not necessary to worry about the inclusion of '/' characters or that the user ID may contain characters that need to be percent encoded. UriBuilder takes care of such details.

UriBuilder can be used to build/replace query or matrix parameters. URI templates can also be declared, for example the following will build the URI "http://localhost/segment?name=value":

Example 5.2. Building URIs using query parameters

UriBuilder.fromUri("http://localhost/").
    path("{a}").
    queryParam("name", "{value}").
    build("segment", "value");


Chapter 6. Deploying a RESTful Web Service

JAX-RS provides a deployment agnostic abstract class Application for declaring root resource and provider classes, and root resource and provider singleton instances. A Web service may extend this class to declare root resource and provider classes. For example,

Example 6.1. Deployment agnostic application model

public class MyApplication extends Application {
    public Set> getClasses() {
        Set> s = new HashSet>();
        s.add(HelloWorldResource.class);
        return s;
    }
}


Alternatively it is possible to reuse one of Jersey's implementations that scans for root resource and provider classes given a classpath or a set of package names. Such classes are automatically added to the set of classes that are returned by getClasses. For example, the following scans for root resource and provider classes in packages "org.foo.rest", "org.bar.rest" and in any sub-packages of those two:

Example 6.2. Reusing Jersey implementation in your custom application model

public class MyApplication extends PackagesResourceConfig {
    public MyApplication() {
        super("org.foo.rest;org.bar.rest");
    }
}




There are multiple deployment options for the class that implements Application interface in the Servlet 3.0 container. For simple deployments, no web.xml is needed at all. Instead, an @ApplicationPath annotation can be used to annotate the user defined application class and specify the the base resource URI of all application resources:

Example 6.3. Deployment of a JAX-RS application using @ApplicationPath with Servlet 3.0

@ApplicationPath("resources")
public class MyApplication extends PackagesResourceConfig {
    public MyApplication() {
        super("org.foo.rest;org.bar.rest");
    }
    ...
}

You also need to set maven-war-plugin attribute to false in pom.xml when building .war without web.xml file using maven:

Example 6.4. Configuration of maven-war-plugin in pom.xml with Servlet 3.0


 ...
 
   org.apache.maven.plugins
   maven-war-plugin
   2.1.1
  
       false
  

  

 ...
 


Another deployment option is to declare JAX-RS application details in the web.xml. This is usually suitable in case of more complex deployments, e.g. when security model needs to be properly defined or when additional initialization parameters have to be passed to Jersey runtime. JAX-RS 1.1 specifies that a fully qualified name of the class that implements Application may be declared in the element of the JAX-RS application's web.xml. This is supported in a Web container implementing Servlet 3.0 as follows:

Example 6.5. Deployment of a JAX-RS application using web.xml with Servlet 3.0


   
        org.foo.rest.MyApplication
   

    ...
   
        org.foo.rest.MyApplication
        /resources
   

    ...


Note that the element is omitted from the servlet declaration. This is a correct declaration utilizing the Servlet 3.0 extension mechanism. Also note that is used to define the base resource URI.

When running in a Servlet 2.x then instead it is necessary to declare the Jersey specific servlet and pass the Application implementation class name as one of the servlet's init-param entries:

Example 6.6. Deployment of your application using Jersey specific servlet


   
        Jersey Web Application
        com.sun.jersey.spi.container.servlet.ServletContainer
       
            javax.ws.rs.Application
            org.foo.rest.MyApplication
       

        ...
   

    ...





Alternatively a simpler approach is to let Jersey choose the PackagesResourceConfig implementation automatically by declaring the packages as follows:

Example 6.7. Using Jersey specific servlet without an application model instance


   
        Jersey Web Application
        com.sun.jersey.spi.container.servlet.ServletContainer
       
            com.sun.jersey.config.property.packages
            org.foo.rest;org.bar.rest
       

        ...
   

    ...


JAX-RS also provides the ability to obtain a container specific artifact from an Application instance. For example, Jersey supports using Grizzly as follows:

1 SelectorThread st = RuntimeDelegate.createEndpoint(new MyApplication(), SelectorThread.class);

Jersey also provides Grizzly helper classes to deploy the ServletThread instance at a base URL for in-process deployment.

The Jersey samples provide many examples of Servlet-based and Grizzly-in-process-based deployments.

Chapter 7. Client API

Table of Contents

7.1. Uniform Interface Constraint
7.2. Ease of use and reusing JAX-RS artifacts
7.3. Getting started with the Jersey client
7.4. Overview of the API
7.4.1. Configuring a Client and WebResource
7.4.2. Building a request
7.4.3. Receiving a response
7.4.4. Creating new WebResources from a WebResource
7.4.5. Java instances and types for representations
7.5. Adding support for new representations
7.6. Using filters
7.6.1. Supported filters
7.7. Testing services
7.8. Security with Http(s)URLConnection
7.8.1. With Http(s)URLConnection
7.8.2. With Apache HTTP client

This section introduces the JAX-RS Client API, which is a high-level Java based API for interoperating with RESTful Web services. It makes it very easy to interoperate with RESTful Web services and enables a developer to concisely and efficiently implement a reusable client-side solution that leverages existing and well established client-side HTTP implementations.

The client API can be utilized to interoperate with any RESTful Web service, implemented using one of many frameworks, and is not restricted to services implemented using JAX-RS. However, developers familiar with JAX-RS should find the client API complementary to their services, especially if the client API is utilized by those services themselves, or to test those services.

The goals of the client API are threefold:

Encapsulate a key constraint of the REST architectural style, namely the Uniform Interface Constraint and associated data elements, as client-side Java artifacts;

Make it as easy to interoperate with RESTful Web services as the JAX-RS server-side API makes it easy to build RESTful Web services; and

Share common concepts of the JAX-RS API between the server and the client side.

The Client API supports a pluggable architecture to enable the use of different underlying HTTP client implementations. Several such implementations are supported by Jersey. To name a few we have a client connectors for Http(s)URLConnection classes supplied with the JDK; and the Grizzly client.

TODO: REWRITE THE FOLLOWING SECTIONS TO THE NEW JAX-RS 2.0 API

7.1. Uniform Interface Constraint

The uniform interface constraint bounds the architecture of RESTful Web services so that a client, such as a browser, can utilize the same interface to communicate with any service. This is a very powerful concept in software engineering that makes Web-based search engines and service mash-ups possible. It induces properties such as:

simplicity, the architecture is easier to understand and maintain; and

modifiability or loose coupling, clients and services can evolve over time perhaps in new and unexpected ways, while retaining backwards compatibility.

Further constraints are required:

every resource is identified by a URI;

a client interacts with the resource via HTTP requests and responses using a fixed set of HTTP methods;

one or more representations can be retured and are identified by media types; and

the contents of which can link to further resources.

The above process repeated over and again should be familiar to anyone who has used a browser to fill in HTML forms and follow links. That same process is applicable to non-browser based clients.

Many existing Java-based client APIs, such as the Apache HTTP client API or java.net.HttpURLConnection supplied with the JDK place too much focus on the Client-Server constraint for the exchanges of request and responses rather than a resource, identified by a URI, and the use of a fixed set of HTTP methods.

A resource in the Jersey client API is an instance of the Java class WebResource, and encapsulates a URI. The fixed set of HTTP methods are methods on WebResource or if using the builder pattern (more on this later) are the last methods to be called when invoking an HTTP method on a resource. The representations are Java types, instances of which, may contain links that new instances of WebResource may be created from.

7.2. Ease of use and reusing JAX-RS artifacts

Since a resource is represented as a Java type it makes it easy to configure, pass around and inject in ways that is not so intuitive or possible with other client-side APIs.

The Jersey Client API reuses many aspects of the JAX-RS and the Jersey implementation such as:

URI building using UriBuilder and UriTemplate to safely build URIs;

Support for Java types of representations such as byte[], String, InputStream, File, DataSource and JAXB beans in addition to Jersey specific features such as JSON support and MIME Multipart support.

Using the builder pattern to make it easier to construct requests.

Some APIs, like the Apache HTTP client or java.net.HttpURLConnection, can be rather hard to use and/or require too much code to do something relatively simple.

This is why the Jersey Client API provides support for wrapping HttpURLConnection and the Apache HTTP client. Thus it is possible to get the benefits of the established implementations and features while getting the ease of use benefit.

It is not intuitive to send a POST request with form parameters and receive a response as a JAXB object with such an API. For example with the Jersey API this is very easy:

Example 7.1. POST request with form parameters

Form f = new Form();
f.add("x", "foo");
f.add("y", "bar");
 
Client c = Client.create();
WebResource r = c.resource("http://localhost:8080/form");
 
JAXBBean bean = r.
    type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
    .accept(MediaType.APPLICATION_JSON_TYPE)
    .post(JAXBBean.class, f);


In the above code a Form is created with two parameters, a new WebResource instance is created from a Client then the Form instance is POSTed to the resource, identified with the form media type, and the response is requested as an instance of a JAXB bean with an acceptable media type identifying the Java Script Object Notation (JSON) format. The Jersey client API manages the serialization of the Form instance to produce the request and de-serialization of the response to consume as an instance of a JAXB bean.

If the code above was written using HttpURLConnection then the developer would have to write code to serialize the form sent in the POST request and de-serialize the response to the JAXB bean. In addition further code would have to be written to make it easy to reuse the same resource “http://localhost:8080/form” that is encapsulated in the WebResource type.

7.3. Getting started with the Jersey client

Refer to the dependencies chapter, and specifically the Core client section, for details on the dependencies when using the Jersey client with Maven and Ant.

Refer to the Java API documentation for details on the Jersey client API packages and classes.

Refer to the Java API Apache HTTP client documentation for details on how to use the Jersey client API with the Apache HTTP client.

7.4. Overview of the API

To utilize the client API it is first necessary to create an instance of a Client, for example:

1 Client c = Client.create();


7.4.1. Configuring a Client and WebResource

The client instance can then be configured by setting properties on the map returned from the getProperties methods or by calling the specific setter methods, for example the following configures the client to perform automatic redirection for appropriate responses:

c.getProperties().put(
    ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);

which is equivalent to the following:

 c.setFollowRedirects(true);

Alternatively it is possible to create a Client instance using a ClientConfig object for example:

ClientConfig cc = new DefaultClientConfig();
cc.getProperties().put(
    ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);
Client c = Client.create(cc);


Once a client instance is created and configured it is then possible to obtain a WebResource instance, which will inherit the configuration declared on the client instance. For example, the following creates a reference to a Web resource with the URI “http://localhost:8080/xyz”:

WebResource r = c.resource("http://localhost:8080/xyz");

and redirection will be configured for responses to requests invoked on the Web resource.

Client instances are expensive resources. It is recommended a configured instance is reused for the creation of Web resources. The creation of Web resources, the building of requests and receiving of responses are guaranteed to be thread safe. Thus a Client instance and WebResource instances may be shared between multiple threads.

In the above cases a WebResource instance will utilize HttpUrlConnection or HttpsUrlConnection, if the URI scheme of the WebResource is “http” or “https” respectively.

7.4.2. Building a request

Requests to a Web resource are built using the builder pattern (see RequestBuilder) where the terminating method corresponds to an HTTP method (see UniformInterface). For example,

 String response = r.accept(
    MediaType.APPLICATION_JSON_TYPE,
    MediaType.APPLICATION_XML_TYPE).
    header("X-FOO", "BAR").
    get(String.class);


The above sends a GET request with an Accept header of application/json, application/xml and a non-standard header X-FOO of BAR.

If the request has a request entity (or representation) then an instance of a Java type can be declared in the terminating HTTP method, for PUT, POST and DELETE requests. For example, the following sends a POST request:

 String request = "content";
String response = r.accept(
    MediaType.APPLICATION_JSON_TYPE,
    MediaType.APPLICATION_XML_TYPE).
    header("X-FOO", "BAR").
    post(String.class, request);

where the String "content" will be serialized as the request entity (see the section "Java instances and types for representations" section for further details on the supported Java types). The Content-Type of the request entity may be declared using the type builder method as follows:

String response = r.accept(
     MediaType.APPLICATION_JSON_TYPE,
     MediaType.APPLICATION_XML_TYPE).
     header("X-FOO", "BAR").
     type(MediaType.TEXT_PLAIN_TYPE).
     post(String.class, request);

or alternatively the request entity and type may be declared using the entity method as follows:

String response = r.accept(
     MediaType.APPLICATION_JSON_TYPE,
     MediaType.APPLICATION_XML_TYPE).
     header("X-FOO", "BAR").
     entity(request, MediaType.TEXT_PLAIN_TYPE).
     post(String.class);


7.4.3. Receiving a response

If the response has a entity (or representation) then the Java type of the instance required is declared in the terminating HTTP method. In the above examples a response entity is expected and an instance of String is requested. The response entity will be de-serialized to a String instance.

If response meta-data is required then the Java type ClientResponse can be declared from which the response status, headers and entity may be obtained. For example, the following gets both the entity tag and response entity from the response:

ClientResponse response = r.get(ClientResponse.class);
EntityTag e = response.getEntityTag();
String entity = response.getEntity(String.class);

If the ClientResponse type is not utilized and the response status is greater than or equal to 300 then the runtime exception UniformInterfaceException is thrown. This exception may be caught and the ClientResponse obtained as follows:

try {
    String entity = r.get(String.class);
} catch (UniformInterfaceException ue) {
    ClientResponse response = ue.getResponse();
}

7.4.4. Creating new WebResources from a WebResource


A new WebResource can be created from an existing WebResource by building from the latter's URI. Thus it is possible to build the request URI before building the request. For example, the following appends a new path segment and adds some query parameters:

WebResource r = c.resource("http://localhost:8080/xyz");

MultivaluedMap params = MultivaluedMapImpl();
params.add("foo", "x");
params.add("bar", "y");

String response = r.path("abc").
    queryParams(params).
    get(String.class);

that results in a GET request to the URI "http://localhost:8080/xyz/abc?foo=x&bar=y".

7.4.5. Java instances and types for representations


All the Java types for representations supported by the Jersey server side for requests and responses are also supported on the client side. This includes the standard Java types as specified by JAX-RS in section 4.2.4 in addition to JSON, Atom and Multipart MIME as supported by Jersey.

To process a response entity (or representation) as a stream of bytes use InputStream as follows:

 InputStream in = r.get(InputStream.class);
// Read from the stream
in.close();

Note that it is important to close the stream after processing so that resources are freed up.

To POST a file use File as follows:

File f = ...
String response = r.post(String.class, f);

Refer to the JAXB sample to see how JAXB with XML and JSON can be utilized with the client API (more specifically, see the unit tests).

7.5. Adding support for new representations

The support for new application-defined representations as Java types requires the implementation of the same provider-based interfaces as for the server side JAX-RS API, namely MessageBodyReader and MessageBodyWriter, respectively, for request and response entities (or inbound and outbound representations). Refer to the entity provider sample for such implementations utilized on the server side.

Classes or implementations of the provider-based interfaces need to be registered with a ClientConfig and passed to the Client for creation. The following registers a provider class MyReader which will be instantiated by Jersey:

ClientConfig cc = new DefaultClientConfig();
cc.getClasses().add(MyReader.class);
Client c = Client.create(cc);

The following registers an instance or singleton of MyReader:

ClientConfig cc = new DefaultClientConfig();
MyReader reader = ...
cc.getSingletons().add(reader);
Client c = Client.create(cc);

7.6. Using filters

Filtering requests and responses can provide useful functionality that is hidden from the application layer of building and sending requests, and processing responses. Filters can read/modify the request URI, headers and entity or read/modify the response status, headers and entity.

The Client and WebResource classes extend from Filterable and that enables the addition of ClientFilter instances. A WebResource will inherit filters from its creator, which can be a Client or another WebResource. Additional filters can be added to a WebResource after it has been created. For requests, filters are applied in reverse order, starting with the WebResource filters and then moving to the inherited filters. For responses, filters are applied in order, starting with inherited filters and followed by the filters added to the WebResource. All filters are applied in the order in which they were added. For instance, in the following example the Client has two filters added, filter1 and filter2, in that order, and the WebResource has one filter added, filter3:

ClientFilter filter1 = ...
ClientFilter filter2 = ...
Client c = Client.create();
c.addFilter(filter1);
c.addFilter(filter2);

ClientFilter filter3 = ...
WebResource r = c.resource(...);
r.addFilter(filter3);

After a request has been built the request is filtered by filter3, filter2 and filter1 in that order. After the response has been received the response is filtered by filter1, filter2 and filter3 in that order, before the response is returned.

Filters are implemented using the “russian doll” stack-based pattern where a filter is responsible for calling the next filter in the ordered list of filters (or the next filter in the “chain” of filters). The basic template for a filter is as follows:

class AppClientFilter extends ClientFilter {
    public ClientResponse handle(ClientRequest cr) {
        // Modify the request
        ClientRequest mcr = modifyRequest(cr);
        // Call the next filter
        ClientResponse resp = getNext().handle(mcr);
        // Modify the response
        return modifyResponse(resp);
    }
}

The filter modifies the request (if required) by creating a new ClientRequest or modifying the state of the passed ClientRequest before calling the next filter. The call to the next request will return the response, a ClientResponse. The filter modifies the response (if required) by creating a new ClientResponse or modifying the state of the returned ClientResponse. Then the filter returns the modified response. Filters are re-entrant and may be called by multiple threads performing requests and processing responses.

7.6.1. Supported filters

The Jersey Client API currently supports two filters:

A GZIP content encoding filter, GZIPContentEncodingFilter. If this filter is added then a request entity is compressed with the Content-Encoding of gzip, and a response entity if compressed with a Content-Encoding of gzip is decompressed. The filter declares an Accept-Encoding of gzip.

A logging filter, LoggingFilter. If this filter is added then the request and response headers as well as the entities are logged to a declared output stream if present, or to System.out if not. Often this filter will be placed at the end of the ordered list of filters to log the request before it is sent and the response after it is received.

The filters above are good examples that show how to modify or read request and response entities. Refer to the source code of the Jersey client for more details.

7.7. Testing services

The Jersey client API was originally developed to aid the testing of the Jersey server-side, primarily to make it easier to write functional tests in conjunction with the JUnit framework for execution and reporting. It is used extensively and there are currently over 1000 tests.

Embedded servers, Grizzly and a special in-memory server, are utilized to deploy the test-based services. Many of the Jersey samples contain tests that utilize the client API to server both for testing and examples of how to use the API. The samples utilize Grizzly or embedded Glassfish to deploy the services.

The following code snippets are presented from the single unit test HelloWorldWebAppTest of the helloworld-webapp sample. The setUp method, called before a test is executed, creates an instance of the Glassfish server, deploys the application, and a WebResource instance that references the base resource:

 @Override
protected void setUp() throws Exception {
    super.setUp();

    // Start Glassfish
    glassfish = new GlassFish(BASE_URI.getPort());

    // Deploy Glassfish referencing the web.xml
    ScatteredWar war = new ScatteredWar(
        BASE_URI.getRawPath(), new File("src/main/webapp"),
        new File("src/main/webapp/WEB-INF/web.xml"),
        Collections.singleton(
            new File("target/classes").
                toURI().toURL()));
    glassfish.deploy(war);

    Client c = Client.create();
    r = c.resource(BASE_URI);
}

The tearDown method, called after a test is executed, stops the Glassfish server.

 @Override
protected void tearDown() throws Exception {
     super.tearDown();
     glassfish.stop();
}

The testHelloWorld method tests that the response to a GET request to the Web resource returns “Hello World”:

public void testHelloWorld() throws Exception {
    String responseMsg = r.path("helloworld").
        get(String.class);
    assertEquals("Hello World", responseMsg);
}

Note the use of the path method on the WebResource to build from the base WebResource.

7.8. Security with Http(s)URLConnection

7.8.1. With Http(s)URLConnectio
n

The support for security, specifically HTTP authentication and/or cookie management with Http(s)URLConnection is limited due to constraints in the API. There are currently no specific features or properties on the Client class that can be set to support HTTP authentication. However, since the client API, by default, utilizes HttpURLConnection or HttpsURLConnection, it is possible to configure system-wide security settings (which is obviously not sufficient for multiple client configurations).

For HTTP authentication the java.net.Authenticator can be extended and statically registered. Refer to the Http authentication document for more details. For cookie management the java.net.CookieHandler can be extended and statically registered. Refer to the Cookie Management document for more details.

To utilize HTTP with SSL it is necessary to utilize the “https” scheme. For certificate-based authentication see the class HTTPSProperties for how to set javax.net.ssl.HostnameVerifier and javax.net.ssl.SSLContext.

7.8.2. With Apache HTTP client

The support for HTTP authentication and cookies is much better with the Apache HTTP client than with HttpURLConnection. See the Java documentation for the package com.sun.jersey.client.apache, ApacheHttpClientState and ApacheHttpClientConfig for more details.




RESTful

RESTful Webservices with Java (Jersey / JAX-RS)

This tutorial explains how to develop RESTful web services in Java with the JAX-RS reference implementation Jersey.

In this tutorial Eclipse 4.2 (Juno), Java 1.6, Tomcat 6.0 and JAX-RS 1.1. (Jersey 1.5) is used.


--------------------------------------------------------------------------------

Table of Contents

1. REST - Representational State Transfer
1.1. Overview
1.2. HTTP methods
1.3. RESTFul webservices
2. JAX-RS with Jersey
2.1. JAX-RS and Jersey
2.2. JAX-RS annotations
3. Installation
3.1. Jersey
3.2. Eclipse and Tomcat
4. Prerequisites
5. Create your first RESTful Webservice
5.1. Create project with Jersey libraries
5.2. Java Class
5.3. Define Jersey Servlet dispatcher
5.4. Run your rest service
5.5. Create a client
6. Restful webservices and JAXB
6.1. Create project
6.2. Create a client
7. CRUD RESTful webservice
7.1. Project
7.2. Create a simple HTML form
7.3. Rest Service
7.4. Run
7.5. Create a client
7.6. Using the rest service via HTML page
7.7. Using the rest service via X
8. Thank you
9. Questions and Discussion
10. Links and Literature
10.1. Source Code
10.2. Rest Resources
10.3. vogella Resources


1. REST - Representational State Transfer
 
1.1. Overview 

REST is an architectural style which is based on web-standards and the HTTP protocol. REST was first described by Roy Fielding in 2000.

In a REST based architecture everything is a resource. A resource is accessed via a common interface based on the HTTP standard methods.

In a REST based architecture you typically have a REST server which provides access to the resources and a REST client which accesses and modify the REST resources.

Every resource should support the HTTP common operations. Resources are identified by global IDs (which are typically URIs).

REST allows that resources have different representations, e.g. text, xml, json etc. The rest client can ask for specific representation via the HTTP protocol (content negotiation).

1.2. HTTP methods 

The PUT, GET, POST and DELETE methods are typical used in REST based architectures.

The following table gives an explanation of these operations.


GET defines a reading access of the resource without side-effects. The resource is never changed via a GET request, e.g. the request has no side effects (idempotent).

PUT creates a new resource, must also be idempotent.

DELETE removes the resources. The operations are idempotent, they can get repeated without leading to different results.

POST updates an existing resource or creates a new resource.


1.3. RESTFul webservices
 
A RESTFul webservices are based on the HTTP methods and the concept of REST. A RESTFul webservice typically defines the base URI for the services, the supported MIME-types (XML, Text, JSON, user-defined,..) and the set of operations (POST, GET, PUT, DELETE) which are supported.

2. JAX-RS with Jersey
2.1. JAX-RS and Jersey
 
Java defines REST support via the Java Specification Request 311 (JSR). This specificiation is called JAX-RS (The Java API for RESTful Web Services). JAX-RS uses annotations to define the REST relevance of Java classes.

Jersey is the reference implementation for this specification. Jersey contains basically a REST server and a REST client. The core client can be used provides a library to communicate with the server.

On the server side Jersey uses a servlet which scans predefined classes to identify RESTful resources. Via the web.xml configuration file for your web application, registers this servlet which is provided by the Jersey distribution

The base URL of this servlet is:


http://your_domain:port/display-name/url-pattern/path_from_rest_class
This servlet analyzes the incoming HTTP request and selects the correct class and method to respond to this request. This selection is based on annotations in the class and methods.

A REST web application consists therefore out of data classes (resources) and services. These two types are typically maintained in different packages as the Jersey servlet will be instructed via the web.xml to scan certain packages for data classes.

JAX-RS supports the creation of XML and JSON via the Java Architecture for XML Binding (JAXB).

JAXB is described in the JAXB Tutorial .

2.2. JAX-RS annotations 

The most important annotations in JAX-RS are listed in the following table.

Table 1. JAX-RS annotations

Annotation Description
@PATH(your_path) Sets the path to base URL + /your_path. The base URL is based on your application name, the servlet and the URL pattern from the web.xml" configuration file. 
@POST Indicates that the following method will answer to a HTTP POST request 
@GET Indicates that the following method will answer to a HTTP GET request 
@PUT Indicates that the following method will answer to a HTTP PUT request 
@DELETE Indicates that the following method will answer to a HTTP DELETE request 
@Produces(MediaType.TEXT_PLAIN [, more-types ]) @Produces defines which MIME type is delivered by a method annotated with @GET. In the example text ("text/plain") is produced. Other examples would be "application/xml" or "application/json". 
@Consumes(type [, more-types ]) @Consumes defines which MIME type is consumed by this method. 
@PathParam Used to inject values from the URL into a method parameter. This way you inject for example the ID of a resource into the method to get the correct object. 




The complete path to a resource is basd on the base URL and the @PATh annotation in your class.


http://your_domain:port/display-name/url-pattern/path_from_rest_class

3. Installation
3.1. Jersey 

Download Jersey from the Jersey Homepage.


http://jersey.java.net/

As of the time of writing the file is called A zip of Jersey containing the Jersey jars, core dependencies (it does not provide dependencies for third party jars beyond the those for JSON support) and JavaDoc. Download this zip; it contains the jar files required for the REST functionality.

3.2. Eclipse and Tomcat 

This tutorial is using Tomcat as servlet container and Eclipse WTP as a development environment. Please see Eclipse WTP and Apache Tomcat for instructions on how to install and use Eclipse WTP and Apache Tomcat.

Alternative you could also use the Google App Engine for running the server part of the following REST examples. If you use the Google App Engine you do not have to setup Tomcat. If you are using GAE/J you have to create App Engine projects instead of Dynamic Web Project.

4. Prerequisites 

The following description assumes that you are familiar with creating web applications in Eclipse. See Eclipse WTP development for an introduction into creating web applications with Eclipse.

5. Create your first RESTful Webservice
5.1. Create project with Jersey libraries
 
Create a new Dynamic Web Project called de.vogella.jersey.first.




Copy all jars from your Jersey download into the WEB-INF/lib folder.

5.2. Java Class 

Create the following class.


package de.vogella.jersey.first;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

// Plain old Java Object it does not extend as class or implements
// an interface

// The class registers its methods for the HTTP GET request using the @GET annotation.
// Using the @Produces annotation, it defines that it can deliver several MIME types,
// text, XML and HTML.

// The browser requests per default the HTML MIME type.

//Sets the path to base URL + /hello
@Path("/hello")
public class Hello {

  // This method is called if TEXT_PLAIN is request
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  public String sayPlainTextHello() {
    return "Hello Jersey";
  }

  // This method is called if XML is request
  @GET
  @Produces(MediaType.TEXT_XML)
  public String sayXMLHello() {
    return "" + " Hello Jersey" + "";
  }

  // This method is called if HTML is request
  @GET
  @Produces(MediaType.TEXT_HTML)
  public String sayHtmlHello() {
    return " " + "" + "Hello Jersey" + ""
        + "

" + "Hello Jersey" + "


" + " ";
  }

}

This class register itself as a get resource via the @GET annotation. Via the @Produces annotation it defines that it delivers the text and the HTML MIME types. It also defines via the @Path annotation that its service is available under the hello URL.

The browser will always request the html MIME type. To see the text version you can use tool like curl .

5.3. Define Jersey Servlet dispatcher 

You need to register Jersey as the servlet dispatcher for REST requests. Open the file web.xml and modify the file to the following.




  de.vogella.jersey.first
 
    Jersey REST Service
    com.sun.jersey.spi.container.servlet.ServletContainer
   
      com.sun.jersey.config.property.packages
      de.vogella.jersey.first
   

    1
 

 
    Jersey REST Service
    /rest/*
 


The parameter "com.sun.jersey.config.property.package" defines in which package jersey will look for the web service classes. This property must point to your resources classes. The URL pattern defines part of the base URL your application will be placed.

5.4. Run your rest service 

Run you web application in Eclipse. See Eclipse WTP for details on how to run dynamic web applications.

Test your REST service under: "http://localhost:8080/de.vogella.jersey.first/rest/hello". This name is derived from the "display-name" defined in the web.xml file, augmented with the servlet-mapping url-pattern and the "hello" @Path annotation from your class file. You should get the message "Hello Jersey".

The browser requests the HTML representation of your resource. In the next chapter we are going to write a client which will read the XML representation.

5.5. Create a client 

Jersey contains a REST client library which can be used for testing or to build a real client in Java. Alternative you could use Apache HttpClient to create a client.

Create a new Java "de.vogella.jersey.first.client" and add the jersey jars to the project and the project build path. Create the following test class.


package de.vogella.jersey.first.client;

import java.net.URI;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

public class Test {
  public static void main(String[] args) {
    ClientConfig config = new DefaultClientConfig();
    Client client = Client.create(config);
    WebResource service = client.resource(getBaseURI());
    // Fluent interfaces
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(ClientResponse.class).toString());
    // Get plain text
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(String.class));
    // Get XML
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_XML).get(String.class));
    // The HTML
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_HTML).get(String.class));

  }

  private static URI getBaseURI() {
    return UriBuilder.fromUri("http://localhost:8080/de.vogella.jersey.first").build();
  }

}

6. Restful webservices and JAXB 

JAX-RS supports the automatic creation of XML and JSON via JAXB. For an introduction into XML please see Java and XML - Tutorial . For an introduction into JAXB please see JAXB. You can continue this tutorial without reading these tutorials but they contain more background information.

6.1. Create project 

Create a new Dynamic Web Project called de.vogella.jersey.jaxb and copy all jersey jars into the WEB-INF/lib folder.

Create your domain class.


package de.vogella.jersey.jaxb.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
// JAX-RS supports an automatic mapping from JAXB annotated class to XML and JSON
// Isn't that cool?
public class Todo {
  private String summary;
  private String description;
  public String getSummary() {
    return summary;
  }
  public void setSummary(String summary) {
    this.summary = summary;
  }
  public String getDescription() {
    return description;
  }
  public void setDescription(String description) {
    this.description = description;
  }

 
}

Create the following resource class. This class simply return an instance of the Todo class.


package de.vogella.jersey.jaxb;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import de.vogella.jersey.jaxb.model.Todo;

@Path("/todo")
public class TodoResource {
  // This method is called if XMLis request
  @GET
  @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
  public Todo getXML() {
    Todo todo = new Todo();
    todo.setSummary("This is my first todo");
    todo.setDescription("This is my first todo");
    return todo;
  }
 
  // This can be used to test the integration with the browser
  @GET
  @Produces({ MediaType.TEXT_XML })
  public Todo getHTML() {
    Todo todo = new Todo();
    todo.setSummary("This is my first todo");
    todo.setDescription("This is my first todo");
    return todo;
  }

}

Change web.xml to the following.



  xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  id="WebApp_ID" version="2.5">
  de.vogella.jersey.jaxb
 
    Jersey REST Service
    com.sun.jersey.spi.container.servlet.ServletContainer
   
      com.sun.jersey.config.property.packages
      de.vogella.jersey.jaxb
   

    1
 

 
    Jersey REST Service
    /rest/*
 


Run you web application in Eclipse and validate that you can access your service. Your application should be available under the following URL.


http://localhost:8080/de.vogella.jersey.jaxb/rest/todo
6.2. Create a client
Create a new Java "de.vogella.jersey.jaxb.client" and add the jersey jars to the project and the project build path. Create the following test class.


package de.vogella.jersey.jaxb.client;


import java.net.URI;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

public class Test {
  public static void main(String[] args) {
    ClientConfig config = new DefaultClientConfig();
    Client client = Client.create(config);
    WebResource service = client.resource(getBaseURI());
    // Get XML
    System.out.println(service.path("rest").path("todo").accept(MediaType.TEXT_XML).get(String.class));
    // Get XML for application
    System.out.println(service.path("rest").path("todo").accept(MediaType.APPLICATION_JSON).get(String.class));
    // Get JSON for application
    System.out.println(service.path("rest").path("todo").accept(MediaType.APPLICATION_XML).get(String.class));
  }

  private static URI getBaseURI() {
    return UriBuilder.fromUri("http://localhost:8080/de.vogella.jersey.jaxb").build();
  }

}

7. CRUD RESTful webservice 

This section creates a CRUD (Create, Read, Update, Delete) restful web service. It will allow to maintain a list of todos in your web application via HTTP calls.

7.1. Project 

Create a new dynamic project called de.vogella.jersey.todo and add the jersey libs. Change the web.xml file to the following.




  de.vogella.jersey.todo
 
    Jersey REST Service
    com.sun.jersey.spi.container.servlet.ServletContainer
   
      com.sun.jersey.config.property.packages
      de.vogella.jersey.todo.resources
   

    1
 

 
    Jersey REST Service
    /rest/*
 


Create the following data model and a Singleton which serves as the data provider for the model. We use the implementation based on an enumeration. Please see the link for details. The Todo class is annotated with a JAXB annotation. See Java and XML to learn about JAXB.


package de.vogella.jersey.todo.model;


import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Todo {
  private String id;
  private String summary;
  private String description;
 
  public Todo(){
   
  }
  public Todo (String id, String summary){
    this.id = id;
    this.summary = summary;
  }
  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
  public String getSummary() {
    return summary;
  }
  public void setSummary(String summary) {
    this.summary = summary;
  }
  public String getDescription() {
    return description;
  }
  public void setDescription(String description) {
    this.description = description;
  }
 
 
}


package de.vogella.jersey.todo.dao;

import java.util.HashMap;
import java.util.Map;

import de.vogella.jersey.todo.model.Todo;

public enum TodoDao {
  instance;
 
  private Map contentProvider = new HashMap();
 
  private TodoDao() {
   
    Todo todo = new Todo("1", "Learn REST");
    todo.setDescription("Read http://www.vogella.com/articles/REST/article.html");
    contentProvider.put("1", todo);
    todo = new Todo("2", "Do something");
    todo.setDescription("Read complete http://www.vogella.com");
    contentProvider.put("2", todo);
   
  }
  public Map getModel(){
    return contentProvider;
  }
 
}

7.2. Create a simple HTML form 

 
The rest service can be used via HTML forms. The following HTML form will allow to post new data to the service. Create the following page called create_todo.html in the WebContent folder.




 
  Form to create a new resource
 

 

 
 
 

 
 
 

  Description:
 
 

 
 


7.3. Rest Service
Create the following classes which will be used as REST resources.


package de.vogella.jersey.todo.resources;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;

import de.vogella.jersey.todo.dao.TodoDao;
import de.vogella.jersey.todo.model.Todo;

public class TodoResource {
  @Context
  UriInfo uriInfo;
  @Context
  Request request;
  String id;
  public TodoResource(UriInfo uriInfo, Request request, String id) {
    this.uriInfo = uriInfo;
    this.request = request;
    this.id = id;
  }
 
  //Application integration    
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public Todo getTodo() {
    Todo todo = TodoDao.instance.getModel().get(id);
    if(todo==null)
      throw new RuntimeException("Get: Todo with " + id +  " not found");
    return todo;
  }
 
  // For the browser
  @GET
  @Produces(MediaType.TEXT_XML)
  public Todo getTodoHTML() {
    Todo todo = TodoDao.instance.getModel().get(id);
    if(todo==null)
      throw new RuntimeException("Get: Todo with " + id +  " not found");
    return todo;
  }
 
  @PUT
  @Consumes(MediaType.APPLICATION_XML)
  public Response putTodo(JAXBElement todo) {
    Todo c = todo.getValue();
    return putAndGetResponse(c);
  }
 
  @DELETE
  public void deleteTodo() {
    Todo c = TodoDao.instance.getModel().remove(id);
    if(c==null)
      throw new RuntimeException("Delete: Todo with " + id +  " not found");
  }
 
  private Response putAndGetResponse(Todo todo) {
    Response res;
    if(TodoDao.instance.getModel().containsKey(todo.getId())) {
      res = Response.noContent().build();
    } else {
      res = Response.created(uriInfo.getAbsolutePath()).build();
    }
    TodoDao.instance.getModel().put(todo.getId(), todo);
    return res;
  }
 
 

}


package de.vogella.jersey.todo.resources;


import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import de.vogella.jersey.todo.dao.TodoDao;
import de.vogella.jersey.todo.model.Todo;


// Will map the resource to the URL todos
@Path("/todos")
public class TodosResource {

  // Allows to insert contextual objects into the class,
  // e.g. ServletContext, Request, Response, UriInfo
  @Context
  UriInfo uriInfo;
  @Context
  Request request;


  // Return the list of todos to the user in the browser
  @GET
  @Produces(MediaType.TEXT_XML)
  public List getTodosBrowser() {
    List todos = new ArrayList();
    todos.addAll(TodoDao.instance.getModel().values());
    return todos;
  }
 
  // Return the list of todos for applications
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public List getTodos() {
    List todos = new ArrayList();
    todos.addAll(TodoDao.instance.getModel().values());
    return todos;
  }
 
 
  // retuns the number of todos
  // Use http://localhost:8080/de.vogella.jersey.todo/rest/todos/count
  // to get the total number of records
  @GET
  @Path("count")
  @Produces(MediaType.TEXT_PLAIN)
  public String getCount() {
    int count = TodoDao.instance.getModel().size();
    return String.valueOf(count);
  }
 
  @POST
  @Produces(MediaType.TEXT_HTML)
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public void newTodo(@FormParam("id") String id,
      @FormParam("summary") String summary,
      @FormParam("description") String description,
      @Context HttpServletResponse servletResponse) throws IOException {
    Todo todo = new Todo(id,summary);
    if (description!=null){
      todo.setDescription(description);
    }
    TodoDao.instance.getModel().put(id, todo);
   
    servletResponse.sendRedirect("../create_todo.html");
  }
 
 
  // Defines that the next path parameter after todos is
  // treated as a parameter and passed to the TodoResources
  // Allows to type http://localhost:8080/de.vogella.jersey.todo/rest/todos/1
  // 1 will be treaded as parameter todo and passed to TodoResource
  @Path("{todo}")
  public TodoResource getTodo(@PathParam("todo") String id) {
    return new TodoResource(uriInfo, request, id);
  }
 
}

This TodosResource uses the @PathParam "annotation to define that the id is inserted as parameter.

7.4. Run
Run you web application in Eclipse and test the availability of your REST service under: "http://localhost:8080/de.vogella.jersey.todo/rest/todos". You should see the XML representation of your Todo items.




To see the count of Todo items use "http://localhost:8080/de.vogella.jersey.todo/rest/todos/count" to see an exiting todo use "http://localhost:8080/de.vogella.jersey.todo/rest/todos/{id}", e.g. "http://localhost:8080/de.vogella.jersey.todo/rest/todos/1" to see the todo with ID 1. We currently have only todos with the id's 1 and 2, all other requests will result an HTTP error code.

Please note that with the browser you can only issue HTTP GET requests. The next chapter will use the jersey client libraries to issue get, post and delete.

7.5. Create a client

 
Create a new Java project called de.vogella.jersey.todo.client. Create a lib folder and place all jersey libs in this folder. Add the jars to the classpath of the project.

Create the following class.


package de.vogella.jersey.todo.client;

import java.net.URI;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.representation.Form;

import de.vogella.jersey.todo.model.Todo;

public class Tester {
  public static void main(String[] args) {
    ClientConfig config = new DefaultClientConfig();
    Client client = Client.create(config);
    WebResource service = client.resource(getBaseURI());
    // Create one todo
    Todo todo = new Todo("3", "Blabla");
    ClientResponse response = service.path("rest").path("todos")
        .path(todo.getId()).accept(MediaType.APPLICATION_XML)
        .put(ClientResponse.class, todo);
    // Return code should be 201 == created resource
    System.out.println(response.getStatus());
    // Get the Todos
    System.out.println(service.path("rest").path("todos")
        .accept(MediaType.TEXT_XML).get(String.class));
    // Get JSON for application
    System.out.println(service.path("rest").path("todos")
        .accept(MediaType.APPLICATION_JSON).get(String.class));
    // Get XML for application
    System.out.println(service.path("rest").path("todos")
        .accept(MediaType.APPLICATION_XML).get(String.class));

    // Get the Todo with id 1
    System.out.println(service.path("rest").path("todos/1")
        .accept(MediaType.APPLICATION_XML).get(String.class));
    // get Todo with id 1
    service.path("rest").path("todos/1").delete();
    // Get the all todos, id 1 should be deleted
    System.out.println(service.path("rest").path("todos")
        .accept(MediaType.APPLICATION_XML).get(String.class));

    // Create a Todo
    Form form = new Form();
    form.add("id", "4");
    form.add("summary", "Demonstration of the client lib for forms");
    response = service.path("rest").path("todos")
        .type(MediaType.APPLICATION_FORM_URLENCODED)
        .post(ClientResponse.class, form);
    System.out.println("Form response " + response.getEntity(String.class));
    // Get the all todos, id 4 should be created
    System.out.println(service.path("rest").path("todos")
        .accept(MediaType.APPLICATION_XML).get(String.class));

  }

  private static URI getBaseURI() {
    return UriBuilder.fromUri("http://localhost:8080/de.vogella.jersey.todo").build();
  }
}

7.6. Using the rest service via HTML page

 
The above example contains a form which calls a post method of your rest service.

7.7. Using the rest service via X 

 
Usually every programming language provide somewhere libraries for creating HTTP get, post, put and delete requests. For Java the project Apache HttpClient.

8. Thank you 



One More Example:

HelloWorldService.java

package com.test.rest;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/hello")
public class HelloWorldService {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getMsg(@QueryParam("one") String a,
            @QueryParam("two") String b) {
        int sum = Integer.parseInt(a) + Integer.parseInt(b);

        return Response.status(200).entity(sum).build();

    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response getSum(Calculator calculator) {

        return Response.status(200).entity(calculator.getOne()).build();
    }

}



Calculator.java

package com.test.rest;

public class Calculator {

    String one;

    public String getOne() {
        return one;
    }

    public void setOne(String one) {
        this.one = one;
    }

}
 

web.xml

    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    Restful Web Application

   
        jersey-serlvet
        com.sun.jersey.spi.container.servlet.ServletContainer
        
            com.sun.jersey.config.property.packages
            com.test.rest
        

        
            com.sun.jersey.api.json.POJOMappingFeature
            true
       

        1
   


   
        jersey-serlvet
        /rest/*
   

   
   
    index.jsp
   




jar files list:

appserv-rt.jar
javax.ws.rs.jar
jersey-client-1.1.5.1.jar
jersey-client-1.4-sources.jar
jersey-core-1.1.5.1.jar


I used for this example Glassfish Server.