Guide to Core JAX-RS Concepts

In the previous article, we have discussed the Jersey Hello-World Example. This article presents an overview of the important core JAX-RS concepts:

Table of Contents

1. Root Resources
2. Useful JAX-RS annotations
3. Sub-resources
4. Sub-resource locators
5. HTTP methods

1. Root Resource

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 (resource method designator annotation such as @GET@PUT@POST@DELETE).
Example: A sample code example is a very simple example of a root resource class using JAX-RS annotations.
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;
    }
}

2. Useful JAX-RS annotations

The @Path Annotation

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}")
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: 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 username 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:
@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")
In this type of example, the username variable will only match usernames that begin with one upper or lower case letter and zero or more alphanumeric characters and the underscore character. If a username does not match that a 404 (Not Found) response will occur.
@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.
@GET, @PUT, @POST, @DELETE, ... (HTTP Methods)

The @GET HTTP Method Annotation

Methods annotation with the @GET annotation respond to HTTP get requests.
@GET annotation used for getting operations.
Example: get all the books from the database.
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAllBooks() {
    List<Book> books = BookRepository.getAllBooks(); // queries database for all books
    GenericEntity<List<Book>> list = new GenericEntity<List<Book>>(books) {};
    return Response.ok(list).build();
}
Note that the GenericEntity wrapper is used to maintain the generic type of the List as Book.

The @POST HTTP Method Annotation

Methods annotated @POST respond to POST method requests.
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response saveBook(Book book) {
    book = bookRepository.saveBook(book);
    return Response.ok(book).build();
}
The POST HTTP method is commonly used to create a resource. This example code persists the new book object in the database.

The @PUT HTTP Method Annotation

The @PUT annotation is used for updating a record and method annotated this way respond to an HTTP PUT request.
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updateBook(Book book) {
    book = bookRepository.updateBook(book);
    return Response.ok(book).build();
}

The @DELETE HTTP Method Annotation

Methods annotated @DELETE are expected to delete a resource.
@DELETE
@Path("{isbn}")
@Produces(MediaType.APPLICATION_JSON)
public Response deleteBook(@PathParam("isbn") String isbn) {
    Book book = bookRepository.deleteBookByIsbn(isbn);
    return Response.ok(book).build();
}
Usually, the resource or its id is passed to the resource method parameter from the URI variable as you can see in this example.

The @OPTIONS HTTP Method Annotation

Methods annotated with @OPTIONS respond to HTTP Option requests.
@OPTIONS
public Response preflight() {
    return Response.ok().header("Allow", true).build();
}
The options method is used as a request when the client wishes to make a complex HTTP request to a different domain. It is done in order to determine if the client is allowed to make the request or not.

The @HEAD HTTP Method Annotation

The HTTP @HEAD method is identical to HTTP GET method except that the server mustn’t respond with a body in the response.
@HEAD
public Response headsUp() {
    return Response.ok().build();
}

@Produces

The@Produces annotation is used to specify the MIME media types of representations a resource can produce and send back to the client.
@Produces can be applied at both the class and method levels. Example: In this example, the Java method will produce representations identified by the MIME media type "text/plain".
@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 @Producessetting, and specifies that the method can produce HTML rather than plain text.
More than one media type may be declared in the same @Produces declaration, for example: 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, the 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: 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 a server always sends "application/json", since "application/xml" has a lower quality factor.

@Consumes

The @Consumes annotation is used to specify the MIME media types of representations that can be consumed by a resource. Example: 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 to the client.
@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.

Parameter Annotation - @PathParam

@PathParam to extract a path parameter from the path component of the request URL that matched the path declared in @Path. Example:
    @Path("{userid}/")
    public String getUser(@PathParam("userid") String userid) {
       // return user object as json
    }
@Path("/users/{username}")
public class UserResource {
 
    @GET
    @Produces("text/xml")
    public String getUser(@PathParam("username") String userName) {
        ...
    }
}

The @QueryParam Annotation

A query parameter is the value associated with the key/value pair appended to a URL after the ?symbol. So for example, in the URL : http://localhost:8080/api/books/search?keyword=Java&limit=10 the query parameters are keyword and limit and the query values are Java and 10.
To retrieve these values use the @QueryParam annotation and pass the name of the query parameter as a value to the annotation, then annotated a method parameter in the resource method that responds to a request to the URI resource /books/search.
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("search")
public Response searchBook(@QueryParam("keyword") String keyword, @QueryParam("limit") int limit) {
    List<Book> books = bookRepository.searchBook(keyword, limit);
    return Response.ok(new GenericEntity<List<Book>>(books) {}).build();
}
In the code snippet above the value of the keyword query parameter is assigned to the method parameter keyword and the value of the limit query parameter is assigned to the limit method parameter.

The @FormParam Annotation

@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: Processing POSTed HTML form
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("name") String name) {
    // Store the message
}
On other words, You may need to read parameters sent in a POST HTTP requests directly from the body, rather than serializing it to an object. This can be done by using the @FormParam annotation.
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response saveBookF(@FormParam("title") String title,
                          @FormParam("author") String author,
                          @FormParam("price") Float price) {
    return Response.ok(bookRepository.saveBook(new Book(title, author, price))).build();
}

The @MatrixParam Annotation

Matrix parameters are a set of query parameters separated by a semicolon rather than an ampersand. This may occur because the values were selected from a multiple select input box and being set via a GET request rather than a POST request. The URL might look something like this:
http://localhost:8080/api/books;author=atheedom;category=Java;language=english
The annotation @MatricParam is used to retrieve the parameter value from the URI and assign it to a method parameter.
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getBookBy(@MatrixParam("author") String author,
                          @MatrixParam("category") String category,
                          @MatrixParam("language") String language) {
    return Response.ok(
            new GenericEntity<List<Book>>(
                    bookRepository.getBookBy(author, category, language)) {}).build();
}

The @CookieParam Annotation

The `@CookieParam` annotation allows you to inject directly into your resource method cookies sent by the client. Imagine you have sent a cookie called cartId to the clients so that you can track the customer’s shopping cart. To pull the cookie from the HTTP request just annotate the method parameter to which you want the cookie data to be assigned.
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getCart(@CookieParam("cartId") int cartId) {
    return Response.ok().build();
}

The @HeaderParam Annotation

The @HeaderParam annotation is used to inject HTTP request header values into resource method parameters. You can think of it like a shortcut to using the @Context annotation to inject theHttpServletRequest or HttpHeaders instance.
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getReferrer(@HeaderParam("referer") String referrer) {
    return Response.ok(referrer).build();
}The @Provider Annotation

The @Provider Annotation

Providers are used to extend and customize JAX-RS by altering the behavior of the runtime to achieve a set of goals.
There are three types of providers:
Entity Providers This type of provider controls the mapping of data representations, such as JSON and XML, to their object equivalents Context Providers This type of provider controls the context that resources can access with the @Context annotation Exception Providers This type of provider controls the mapping of Java exceptions to a JAX-RS Response instance. The only thing they have in common is that they must be identified by the @Provider annotation and follow the correct rules for constructor declaration.
The @ApplicationPath Annotation Let’s start at the top of the trees with the @ApplicationPath annotation:
@ApplicationPath("/api")
public class RESTConfig extends Application {}
This is where you start defining the URI to your resources. Here we are saying that all our resources are to be found at the root /api. The URL should look something like this:
http://localhost:8080/webcontext/api/ 
where webcontext is the name of your application.

3. Sub-resources

@Path may be used on classes and such classes are referred to as root resource classes. @Pathmay 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:
@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) { ... }
}

4. Sub-resource locators

@Path may be used is on methods not annotated with resource method designators such as @GETor @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: 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 @Context Annotation

When deploying a JAX-RS application using servlet then ServletConfig, ServletContext, HttpServletRequest, and HttpServletResponse are available using @Context.
JAX-RS provides the @Context annotation to inject a variety of resources in your RESTful services. Some of the most commonly injected components are HTTP headers, HTTP URI related information. Here is a complete list (in no specific order)
HTTP headers HTTP URI details Security Context Resource Context Request Configuration Application Providers
Example:
@Path("testinject")
public class InjectURIDetails{
    //localhost:8080/<root-context>/testinject/httpheaders
    @GET
    @Path("httpheaders")
    public void test(@Context HttpHeaders headers){
        System.out.println("ALL headers -- "+ headers.getRequestHeaders().toString());
        System.out.println("'Accept' header -- "+ headers.getHeaderString("Accept"));
        System.out.println("'TestCookie' value -- "+ headers.getCookies().get("TestCookie").getValue());
    }
}
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;
    }
}

5. HTTP methods

Resource operations can be performed by using HTTP methods (GET, POST, PUT, DELETE). In ROA, HTTP methods are called as “Unified interface”. It implies that HTTP methods can be executed for all the resources published on the Web and that the meaning of HTTP method does not change with each resource. The association of resource operations assigned to HTTP methods and the post-conditions ensured by each operation is explained below.
Sr. No.HTTP methodResource operationsPost-conditions that the operation should ensure
(1)
GET
Resource is fetched.
Safety, idempotency.
(2)
POST
Resource is created.
Server assigns the URI for created resource, this assigned URI is set to Location header of response and is returned to client.
(4)
PUT
Resource is created or updated.
Idempotency.
(5)
PATCH
Resource difference is updated.
Idempotency.
(6)
DELETE
Resource is deleted.
Idempotency.
(7)
HEAD
Meta information of resource is fetched.
Same process as GET is performed and responds with header only.
Safety, Idempotency.
(8)
OPTIONS
Responds with a list of HTTP methods that can be used for resources.


Comments