JAX-RS Core Part I

The first chapter of this book covers the most fundamental concepts associated with the JAX-RS framework. It will cover the following topics

  • Resources: foundation of RESTful applications

  • Basic annotations: for mapping HTTP operations to your methods

  • Sub Resources: JAX-RS takes resources one step ahead

  • Deployment specific APIs: metadata introspected by the JAX-RS runtime during deployment

Resources

From a JAX-RS standpoint, a Resource is nothing but a class. It decorated with metadata (annotation) to further define RESTful behavior

@Path

The @javax.ws.rs.Path annotation defined by the JAX-RS specification is used to map the URI of the incoming HTTP request to RESTful Resources (Java classes and methods). It supports both simple strings as well as regular expressions as values

//Maps a HTTP GET at /books/ to the all() method

@Path("/books")
public class BooksResource {
  @GET
  public Response all(){
  //send HTTP 200 as response
  return Response.ok().build();
 }
}
  • Both Java classes and methods can be annotated with @Path

  • The JAX-RS runtime executes a URI matching process for each incoming HTTP request which in turn takes into account @Path annotations on the class as well as method level.

//Maps a HTTP GET /conferences/42 to the get() method with 42 as the input parameter

@Path("/conferences")
public class ConferencesResource {
  @GET
  @Path("{id}")
  public Response get(@PathParam("id") String id){
  Conference conf = getConf(id);
  return Response.ok(conf).build();
 }
}

We'll cover @PathParam (and other related annotations) in the next chapter

Mapping resource methods to HTTP verbs

Once the URI mapping is taken care of, the next logical step is to match the HTTP verb in the request to what's implemented in your service implementation.

  • A specific set of JAX-RS annotations are used to map standard HTTP operations to Java methods which contain the business logic to handle the request.

  • These cannot be applied to Java classes.

  • Only one such annotation is allowed on a particular method

JAX-RS annotation

Corresponding HTTP Operation

@javax.ws.rs.GET

GET

@javax.ws.rs.PUT

PUT

@javax.ws.rs.POST

POST

@javax.ws.rs.DELETE

DELETE

@javax.ws.rs.HEAD

HEAD

@javax.ws.rs.OPTIONS

OPTIONS

//Mapping HTTP methods to Java methods

@Path("/conferences")
public class ConferencesResource {

  @POST
  public Response create(Conference conf){
  Conference conf = createNewConf(conf);
  return Response.ok(conf.getSchedule()).build();
 }

  @DELETE
  @Path("{id}")
  public Response delete(@PathParam("id") String id){
  Conference conf = removeConf(id);
  return Response.ok().build();
 }

}

The above example demonstrates how different HTTP verbs (on the same URI) result in different methods being invoked on your JAX-RS resource class

  • A HTTP POST (with Conference details) to /conferences results in the invocation of create method

  • A HTTP DELETE (with Conference id as the path parameter) to /conferences/{id} results in the invocation of delete method

Support for OPTIONS

The JAX-RS specification defines sensible defaults for the HTTP OPTIONS command

//a typical JAX-RS resource

@Path("user")
public class UserResource {

    @GET
    @Path("{id}")
    public Response find(@PathParam("id") String id) {
        return Response.ok().build();
    }

    @PUT
    public Response create(/*User user*/) {
        return Response.ok().build();
    }

    @DELETE
    @Path("{id}")
    public Response delete(@PathParam("id") String id) {
        return Response.ok().build();
    }
}

For the JAX-RS resource represented in the above example below, if you execute a HTTP OPTIONS command against the root resource URI, you will get back the WADL as a response

  • If there is an explicit resource method which is annotated with @javax.ws.rs.OPTIONS, then the corresponding logic will be executed and the default behavior would get suppressed

  • This does not mean that you can execute the OPTIONS command at any random URI within your RESTful app. This kicks in after the request matching process and will be applicable only for a valid URI as defined by @Path annotations in your resource classes.

Sub resource locators

Sub Resource locators are components which help you drill down to or choose from a bunch of resources based on some criteria

They enable

  • resource specific logic to be implemented independently rather than mixing various permutations and combinations

  • encapsulation of business logic for handing over control various resources based on criteria

A generic overview of how they work

  • Use URI mapping to execute business logic to dispatch control to specific JAX-RS resource

  • Once the control is transferred, the HTTP request method matching takes place and the specific method in the resource implementation class is invoked

It's important to note that sub resource locators

  • have the @Path annotation (to bind to correct URI)

  • do not contain HTTP method metadata (@GET, @POST etc.)

//Sub Resource Locators in action

@Path("conferences")
public class ConferencesResourceLocator{

    @Path("{id}") 
    public ConferenceResource pick(@PathParam("id") String confID){
        if(confID.equals("devoxx")){
            return DevoxxResourceFactory.get(confID);
        }else if(confID.equals("JavaOne")){
            return JavaOneResourceFactory.get(confID);
        }
    }

}
//Devoxx specific Sub Resource

public class DevoxxResource extends ConferenceResource{

    @Path("{location}/{year}/{talkID}")
    @GET 
    public Response get(@PathParam("year") String year, 
            @PathParam("location") String location,
            @PathParam("talkID") String talkID){

        DevoxxConference con = getDevoxxConferenceTalkDetails(year,location,talkID);
        return Response.ok(con).build();
    }

}
//JavaOne specific Sub Resource

public class JavaOneResource extends ConferenceResource{

    @Path("{year}/{talkID}")
    @GET 
    //JavaOne location is always San Francisco :-)
    public Response get(@PathParam("year") String year,
            @PathParam("talkID") String talkID){

        JavaOneConference con = getJavaOneConferenceTalkDetails(year,talkID);
        return Response.ok(con).build();
    }

}

Runtime behaviour

  • A HTTP GET request to /conferences/devoxx/UK/2015/42-javaeerocks

  • The ConferencesResourceLocator forwards the request to DevoxxResource

  • @GET annotated method (named get) of the the DevoxxResource ends up being invoked

  • The ConferencesResourceLocator will dispatch to the JavaOneResource sub resource implementation in case the first URI path parameter begins with 'JavaOne' e.g. /conferences/JavaOne/2014/42-java8rocks

Deployment specific APIs

JAX-RS applications can be deployed to a variety of environments/containers

  • Java EE containers (Java EE 6 and above)

  • Servlet Containers

  • Java SE environment (with support from embedded HTTP container support e.g. Jetty, Tomcat etc.)

This section briefly talks about which classes and annotations are required to configure a JAX-RS powered REST service in a Java EE (Java EE 7 to be specific) container. These API components provide the necessary information to the JAX-RS container to be able to complete the application deployment/bootstrap process

  • Application

  • @ApplicationPath

Application

A JAX-RS application needs to subclass this (abstract) class. It defines the components of the application and supplies additional metadata. It has a couple of method which can be overridden to return the application resource class

Abstract Method

Description

Set getClasses()

Returns a set of root resource and provider classes

Set getSingletons()

The returned set of instances of root resource and provider classes are only instantiated once

@ApplicationPath

This annotation helps define the root of your JAX-RS service i.e. it defines the base URI of the application. It can only be applied to classes which extend the Application class

//JAX-RS configuration class

@ApplicationPath("rest")
public class RESTConfig extends Application{
    //empty . . . .
}

It's perfectly valid to have an empty implementation if custom configurations are not required

Last updated