Previous Topic

Next Topic

Book Contents

Book Index

Registering JAX-RS Root Resources with JAX-RS Container

Registering JAX-RS Root Resources

Using the JAX-RS Web resource is implemented as a resource class and requests are handled by resource methods. By default a new resource class instance is created by the JAX-RS container for each request to that resource. First the constructor is called, then any requested dependencies are injected, after that the appropriate method is invoked and finally the object is made available for garbage collection.

A resource class is a Java class that uses JAX-RS annotations to implement a corresponding Web resource. Resource classes are POJOs that are annotated with @Path (root resource classes) or have at least one method annotated with @Path and/or a request method designator.

A request method designator is a runtime annotation. It is annotated with the @HttpMethod annotation. JAX-RS defines a set of request method designators for the common HTTP methods: @GET, @POST, @PUT, @DELETE, @HEAD. Methods of a resource class that are annotated with @Path are either sub-resource methods or sub-resource locators:

Resource methods are methods of a resource class annotated with a request method designator.

Example: A Simple JAX-RS Root Resource Definition

The following example demonstrates a simple JAX-RS root resource definition:

@Path("/demo/bookstore/books")
public class BookStoreService {

  @Context
   // injected by the REST container
private HttpServletRequest servletRequest;

  /**
   * Retrieves an {@link BookCollectionResource} representation holding all books available in the store. The
   * {@link BookCollectionResource} representation and all embedded {@link BookResource} representations shall include
   * all of the mandatory and any of the optional fields annotated with {@code RETRIEVE}.
   ....
   */
  @GET
   public Response getBooks() {
     // get available books
// create and initialize a BookCollectionResource books
    ...
     return Response.ok(books).build();
  }

  /**
   * Retrieves an {@link BookResource} representation of book with identifier {@code bookId}. The {@link BookResource}
   * representation shall include all of the mandatory and any of the optional fields annotated with {@code RETRIEVE}.
   ...
   */
  @GET
  @Path( "{bookId}")
   public Response getBook(@PathParam( "bookId")  long bookId) {
     // get the book with identifier bookId
// create and initialize a BookResource book
    ...
     return Response.ok(book).build();
  }

  /**
   * Deletes the book with identifier {@code bookId}.
   ...
   */
  @DELETE
  @Path( "{bookId}")
   public Response deleteBook(@PathParam( "bookId")  long bookId) {
     // remove the book with identifier bookId
    ...
     return Response.noContent().build();
  }

  /**
   * Creates a  new book in the book store based on the data included in the {@link BookResource} representation
   * transferred by the client. The {@link BookResource} representation may include all of the mandatory and any of the
   * optional fields annotated with {@code CREATE}. On successful creation, the response shall include
   * {@link BookResource} representation of the newly created book and Location header identifying the URI of the newly
   * created group resource.
   ...
   */
  @POST
   public Response addBook(BookResource book) {
     // create new  book based on the information enclosed in the BookResource transferred by the client
// reinitialize the BookResource instance book
    ...
  
     // fill in location header in response
      URI location=UriBuilder.fromPath(
          servletRequest.getRequestURL().append('/').append(createdBook.getId()).toString()).build();
     return Response.created(location).entity(book).build();
  }

  /**
   * Updates the book with identifier {@code bookId} based on the  new data included in the {@link BookResource}
   * representation transferred by the client. The {@link BookResource} representation may include all of the mandatory
   * and any of the optional fields annotated with {@code UPDATE}. On successful update, the response shall include the
   * latest {@link BookResource} representation of the newly updated book.
   ...
   */
  @PUT
  @Path( "{bookId}")
   public Response updateBook(@PathParam( "bookId")  long bookId, BookResource book) {
     // find the book and update its fields
// reinitialize the BookResource instance book
    ...
     return Response.ok(book).build();
  }
}

Example: Modeling a Simple Resource via JAXB Annotations

The following example demonstrates modeling a simple resource using JAXB annotations:

/**

* {@code BookResource} represents a book from the book store.

*/

@SuppressWarnings("javadoc")

@XmlRootElement(name = "book")

@XmlType(name = "book")

public class BookResource {

  private Long id;

  private URI href;

  private String title;

  private String author;

  /**

   * Unique book identifier generated by the book store service. {@code GET}

   */

  @XmlElement(name = "id", required = false)

  public Long getId() {

    return id;

  }

  public void setId(Long id) {

    this.id = id;

  }

  /**

   * Unique identifier of this book resource, self link. URIs of other resources in the URI space of this book

   * resource can easily be derived by the self link. {@code GET}

   */

  @XmlElement(name = "href", required = false)

  public URI getHref() {

    return href;

  }

  public void setHref(URI href) {

    this.href = href;

  }

  /**

   * Book title. {@code GET}, {@code PUT}, {@code POST}

   */

  @XmlElement(name = "title", required = true)

  public String getTitle() {

    return title;

  }

  public void setTitle(String title) {

    this.title = title;

  }

  /**

   * Book author. {@code GET}, {@code PUT}, {@code POST}

   */

  @XmlElement(name = "author", required = true)

  public String getAuthor() {

    return author;

  }

  public void setAuthor(String author) {

    this.author = author;

  }  

}

Example: Modeling a Simple Collection Resource via JAXB annotations

The following example demonstrates modeling a simple collection resource using JAXB annotations:

/**

*

* {@code BookCollectionResource} represents a collection of books. The resource holds a collection of

* {@link BookResource} entries and the common fields of collection resources which support pagination. Paging may be

* defined via {@link HttpHeaders#RANGE} and {@link HttpHeaders#CONTENT_RANGE} headers or via

* {@link QueryParameters#OFFSET} and {@link QueryParameters#LIMIT} query parameters.

*/

@SuppressWarnings("javadoc")

@XmlRootElement(name = "books")

@XmlType(name = "books")

public class BookCollectionResource {

  private URI href;

  private Collection<BookResource> entries;

  private Integer offset;

  private Integer limit;

  private URI previous;

  private URI next;

  /**

   * Unique identifier of this book collection resource, self link. URIs for querying and filtering of the collection of

   * book resources represented by this resource can easily be constructed by appending the query parameters to the self link. {@code GET}

   */

  @XmlElement(name = "href", required = false)

  public URI getHref() {

    return href;

  }

  public void setHref(URI href) {

    this.href = href;

  }

  /**

   * Collection of {@link BookResource} representations that satisfy the filtering and limitation constraints given as

   * query parameters. In case there are no books to satisfy the constraints then this field is omitted. {@code GET}

   */

  @XmlElement(name = "entries", required = false)

  public Collection<BookResource> getEntries() {

    return entries;

  }

  public void setEntries(Collection<BookResource> entries) {

    this.entries = entries;

  }

  /**

   * Offset in the collection of resources where the currently retrieved subset of resource representations starts from.

   * The value shall be same as the offset defined the paginated request. {@code GET}

   */

  @XmlElement(name = "offset", required = false, defaultValue = "0")

  public Integer getOffset() {

    return offset;

  }

  public void setOffset(Integer offset) {

    this.offset = offset;

  }

  /**

   * Maximum number of entries in the currently retrieved subset of resource representations. The value shall be same as

   * the limit defined the paginated request. {@code GET}

   */

  @XmlElement(name = "limit", required = false, defaultValue = "10")

  public Integer getLimit() {

    return limit;

  }

  public void setLimit(Integer limit) {

    this.limit = limit;

  }

  /**

   * Link to the previous set of resource representations that satisfy the filtering and limitation constraints for the

   * collection given as query parameters. The size of the set and offset in the resulting collection are provided via

   * pagination rules. In case there are no resource representations to satisfy the constraints then this field is

   * omitted. {@code GET}

   */

  @XmlElement(name = "previous", required = false)

  public URI getPrevious() {

    return previous;

  }

  public void setPrevious(URI previous) {

    this.previous = previous;

  }

  /**

   * Link to the next set of resource representations that satisfy the filtering and limitation constraints for the

   * collection given as query parameters. The size of the set and offset in the resulting collection are provided via

   * pagination rules. In case there are no resource representations to satisfy the constraints then this field is

   * omitted. {@code GET}

   */

  @XmlElement(name = "next", required = false)

  public URI getNext() {

    return next;

  }

  public void setNext(URI next) {

    this.next = next;

  }

}

Registering JAX-RS Resources with Jersey JAX-RS 2.0 Container

The JAX-RS runtime represents Web resources via JAX-RS resources. JAX-RS resources are annotated with @Path (JAX-RS root resource) or have at least one method annotated with @Path and/or a request method designator for handling Web resource requests. JAX-RS root resources are exposed as RESTful web services. For more information about JAX-RS resources and code samples, please see JAX-RS:The Java API for RESTful Web Services > JAX-RS Resources. For more details, examples and tips on how to model the resources which representations are transferred via RESTful web services, please see JAXB: Java Architecture for XML Binding and the guides for using the auxiliaries for developing RESTful web services conforming to the common behaviors and recommendations:

In the context of OSGi, JAX-RS root resource components which are registered as OSGi services are tracked by the OSGi JAX-RS publisher and registered with the Jersey JAX-RS container, thus exposed as RESTful web services accessible through the OSGi HTTP service. It is recommended that the JAX-RS root resource instances are registered under the top level JAX-RS annotated interfaces/classes implemented, as well, in order to improve maintainability and ease debugging procedures.

The following code snippet demonstrates the registration of a JAX-RS root resource as an OSGi service under com.prosyst.mbs.services.rest.demo.bookstore.BookStoreService using declarative services annotations, thus a RESTful web service is exposed through the OSGi HTTP service under /demo/bookstore/books. The complete code of the BookStoreService JAX-RS root resource can be found at JAX-RS: The Java API for RESTful Web Services > JAX-RS Resources

@Component(immediate = true,

           service = BookStoreService.class,

           configurationPolicy = ConfigurationPolicy.IGNORE)

@Path("/demo/bookstore/books")

public class BookStoreService {

   // resource methods definitions

   ...

}