JBoss.orgCommunity Documentation

Chapter 4. Using @Path and @GET, @POST, etc.

4.1. @Path and regular expression mappings
4.2. JAX-RS 2.0 Matching Algorithm

@Path("/library")
public class Library {

   @GET
   @Path("/books")
   public String getBooks() {...}

   @GET
   @Path("/book/{isbn}")
   public String getBook(@PathParam("isbn") String id) {
      // search my database and get a string representation and return it
   }

   @PUT
   @Path("/book/{isbn}")
   public void addBook(@PathParam("isbn") String id, @QueryParam("name") String name) {...}

   @DELETE
   @Path("/book/{id}")
   public void removeBook(@PathParam("id") String id {...}
   
}

Let's say you have the RESTEasy servlet configured and reachable at a root path of http://myhost.com/services. The requests would be handled by the Library class:

The @javax.ws.rs.Path annotation must exist on either the class and/or a resource method. If it exists on both the class and method, the relative path to the resource method is a concatenation of the class and method.

In the @javax.ws.rs package there are annotations for each HTTP method. @GET, @POST, @PUT, @DELETE, and @HEAD. You place these on public methods that you want to map to that certain kind of HTTP method. As long as there is a @Path annotation on the class, you do not have to have a @Path annotation on the method you are mapping. You can have more than one HTTP method as long as they can be distinguished from other methods.

When you have a @Path annotation on a method without an HTTP method, these are called JAXRSResourceLocators.

The @Path annotation is not limited to simple path expressions. You also have the ability to insert regular expressions into @Path's value. For example:

@Path("/resources)
public class MyResource {

   @GET
   @Path("{var:.*}/stuff")
   public String get() {...}
}

The following GETs will route to the getResource() method:

GET /resources/stuff
GET /resources/foo/stuff
GET /resources/on/and/on/stuff

The format of the expression is:

"{" variable-name [ ":" regular-expression ] "}"

The regular-expression part is optional. When the expression is not provided, it defaults to a wildcard matching of one particular segment. In regular-expression terms, the expression defaults to

"([]*)"

For example:

@Path("/resources/{var}/stuff")

will match these:

GET /resources/foo/stuff
GET /resources/bar/stuff

but will not match:

GET /resources/a/bunch/of/stuff

The resource method matching algorithm mandated by JAX-RS 2.1 is more inclusive that that of JAX-RS 2.0. There are three stages in each of the matching algorithms:

  1. Use the request path to choose possible resource classes.
  2. Use the request path to choose possible resource methods.
  3. Use the HTTP verb and media types, coming and going, to choose a final resource method.

In JAX-RS 2.1, step 2 determines the set of matching resource methods and passes it on to step 3. However, in JAX-RS 2.0, that set is sorted, based on properties of @Path values like number of literals, and only the maximal elements are passed on to step 3. It follows that in some cases, the newer algorithm will find some matches that the earlier algoritm misses. For example,

   @Path("/")
   public static class TestResource
   {
      @GET
      @Path("complex/match")
      public String get()
      {
         return "content";
      }

      @POST
      @Path("complex/{param}")
      public String post(@PathParam("param") String param)
      {
         return "<" + param + "/>";
      }
   }

Both methods can match a request with path "complex/match", but get() comes out ahead of post() in the JAX-RS 2.0 sort because it has more literal characters, and only get() is considered in step 3. [For more details about the sort, see the specification for JAX-RS 2.0.] Therefore, a request that expects a POST method will fail.

On the other hand, both methods are passed on to step 3 in the JAX-RS 2.1 algorithm, so post() is available as a potential match.

The algorithm from JAX-RS 2.1 would seem to be preferable, but, in case the earlier behavior is expected for backwards compatibility, RESTEasy provides a configuration switch, "jaxrs.2.0.request.matching", which, if set to "true", will cause the JAX-RS 2.0 matching to be used. The default value, of course, is "false".