Articles
Java Platform, Enterprise Edition
JAX-RS makes development of Java Web services built according to the Representational State Transfer (REST) architectural style both straightforward and natural.
This article introduces you to the Java API for RESTful Web Services (JAX-RS), which resulted from Java Specification Request (JSR) 311 and is a component of the Java Enterprise Edition Platform (Java EE 6). The aim of JAX-RS is to make development of Java Web services built according to the Representational State Transfer (REST) architectural style both straightforward and natural for you, the developer. To this end, where possible, the API offers declarative annotations that allow you to:
JAX-RS also offers a number of utility classes and interfaces to aid with the more dynamic aspects of applications.
When you use JAX-RS, the application is the unit of deployment. All of the files that make up an application are packaged together and deployed into some form of container that supplies HTTP services. A JAX-RS application consists of:
Here is an example Application subclass:
@ApplicationPath("acme")
public class AcmeApplication extends Application {
}
The ApplicationPath annotation specifies the base URI path segment to which all root resource class URIs are relative. By default, all root resource classes and providers packaged with the Application subclass are included in the application. An Application subclass can also specify a subset of the packaged classes by overriding the getClasses method.
Root resource classes provide entry points into the URI space used by the application. Root resource classes are plain old Java objects (POJOs) that are annotated with @Path. Here is an example root resource class:
@Path("widgets")
public class WidgetsResource {
@GET
public WidgetsRepresentation getWidgetList() {
...
}
}
In the above, the root resource class is published at the relative URI widgets. If this class were part of the AcmeApplication shown earlier, then its URI path would be /acme/widgets.
The @GET annotation on the getWidgetList method indicates that the method is a resource method that you want to be called when an HTTP GET request is dispatched for that URI. Additional annotations are provided to support the other common HTTP methods. The set is extensible for other less common methods. The value returned from the method is converted into a response body by an entity provider. Returning a non-void Java type results in a 200 OK response, while a void method results in a 204 No Content response. As you will see shortly, the status returned in a response can be customized.
To expose a single widget as a resource, you can add a sub-resource method to the resource class as follows:
@Path("widgets")
public class WidgetsResource {
@GET
public WidgetsRepresentation getWidgetList() {
...
}
@GET @Path("{id}")
public WidgetRespresentation getWidget(
@PathParam("id") String widgetId) {
...
}
}
In the above, HTTP GET requests for /acme/widgets/{id} will be dispatched to the getWidget method. The {id} indicates that the path is a URI template that will match any URI with the prefix /acme/widgets/ and a single following path segment, e.g., /acme/widgets/foo.
In the previous example, the actual value of the template variable id is extracted from the request with the @Path-Param annotation and supplied as the value of the widgetId method argument. Additional annotations allow you to extract data from other parts of the request: URI query parameters with @Query-Param, URI matrix parameters with @MatrixParam, HTTP headers with @HeaderParam, and, finally, HTTP cookies with @CookieParam.
The type of method argument that carries one of the above annotations is any Java type with a String constructor or with a static method called valueOf or fromString that returns an instance of the type from a single String argument. For HTTP methods that support an entity body, such as POST, you can extract the data in the entity body into a Java method argument. Conversion from the serialized data in the request entity to a Java type is the responsibility of an entity provider, which we will explain shortly.
In addition to the declarative method of extracting request data described above, JAX-RS provides a set of interfaces that may be queried dynamically:
Application subclass created by the JAX-RS runtime.An instance of any of the above interfaces may be injected into a resource class field or method parameter using the @Context annotation, e.g.:
@Path("widgets")
public class WidgetsResource {
@Context SecurityContext sc;
@GET
public WidgetsRepresentation getWidgetList() {
if (sc.isSecure()) {
// Secure channel
...
} else {
// Insecure channel
...
}
}
}
Responses often require a different status code than returned by default and certain types of responses may also require additional metadata in headers. In this case, the method can return an instance of the Response interface. A utility builder class is supplied that simplifies the construction of a custom response, e.g.:
URI locationURI = createResource(...); Response response = Response.status(CREATED) .location(locationURI) .build(); return response;
or, more conveniently:
URI locationURI = createResource(...); Response response = Response.created(locationURI) .build(); return response;
The JAX-RS runtime will convert relative URIs to absolute URIs when necessary and is also responsible for serialization of custom types used as header values.
A RESTful application will use URIs extensively. The JAX-RS UriBuilder provides you with facilities for constructing URIs both from scratch and from existing URIs. It makes it easy for you to construct URIs based on the URI templates contained in @Path annotations. For example:
@Path("widgets")
public class WidgetsResource {
@Context UriInfo ui;
@GET @Path("{id}")
public WidgetRespresentation getWidget(
@PathParam("id") String widgetId) {
...
}
@POST
public Response createWidget(
WidgetRepresentation widget) {
String widgetId = saveWidget(widget);
UriBuilder ub = ui.getRequestUriBuilder();
URI widgetURI = ub
.path(WidgetsResource.class, "getWidget")
.build(widgetId);
return Response.created(widgetURI).build();
}
}
The createWidget method constructs widgetURI using:
{id})extracted from the @Path annotation on the getWidget methodwidgetId.Prior to the call to the build method, the URI builder contains: http://.../acme/widgets/{id}
The arguments to the build method are substituted positionally for the URI template variables. Therefore, if widgetId contained the value ”foo” then the final value of widgetURI will be: http://.../acme/widgets/foo
Exceptions thrown by a resource class method are caught by the JAX-RS runtime and converted to error responses. By default, exceptions are converted to a 500 Server Error response. JAX-RS offers two ways that you can customize the default error response:
WebApplicationException which can contain a customized Response.Response when an exception is caught.
The two above methods can be mixed within an application. The second method is particularly well suited to cases where many methods can throw the same exception(s) since it naturally centralizes error response handling in one place.
As you have seen from prior examples, when dispatching requests to Java methods, the JAX-RS runtime does the following to route the request to the appropriate method:
@Path annotations.@GET, @POST, etc.).Content-Type header) is compared to the value(s) of @Consumes annotations. Accept header) is compared to the value(s) of @Produces annotations. The order above denotes significance from most (request URI) to least (desired response media type). The dispatching algorithm proceeds in a number of phases. The first phase identifies the class whose @Path value most closely matches the request URI, therefore it is the most significant aspect. The value of the @Produces annotation is only considered in the final stage of matching -- therefore it is the least significant aspect. The exact algorithm used to match requests to the appropriate Java method is described in section 3.7 of the JAX-RS specification request.
Here is an example of declarative content negotiation:
@Path("widgets")
public class WidgetsResource {
@GET @Produces("application/xml")
public Document getXml() {...}
@GET @Produces("application/json")
public String getJson() {...}
}
In the above, a GET request for /acme/widgets with an Accept header value application/xml would be dispatched to the getXml method. Likewise, a GET request for the same URI with an Accept header of application/json would be dispatched to the getJson method.
Providers are JAX-RS extensions that supply functionality to the JAX-RS runtime. The two main provider types are entity providers and exception mapping providers.
Entity providers supply serialization and/or deserialization services between resource representations and their associated Java types. An entity provider that supports deserialization of a representation to a Java type implements the MessageBodyReader interface. An entity provider that supports serialization of a Java type to a representation implements the MessageBodyWriter interface.
Inclusion of an entity provider for a particular Java type in a JAX-RS application allows that type to be used as a resource method argument, as the return type for a resource method, or as the type of entity embedded in a returned Response. JAX-RS includes a number of built-in entity providers for common Java types including: String, InputStream, File and application-supplied JAXB classes. Entity providers may use the @Consumes and @Provides annotations to statically declare the media types that they support. They can also determine whether they support a particular media type and Java type at runtime to accommodate more complex providers.
Exception mapping providers supply mapping services between Java exceptions and a JAX-RS Response. Exception mapping providers implement the ExceptionMapper interface and are called when a resource method throws a checked or runtime exception. The Response returned by an exception mapping provider is treated the same as a Response returned by a resource method: it may use any status code and may contain headers. Any contained entity will be serialized using an appropriate entity provider.
JAX-RS is an annotation-driven Java API that aims to make development of Web services built according to the Representational State Transfer (REST) architectural style in Java both straightforward and intuitive for you, the developer. It should enable you to more rapidly build lightweight web services that conform to the REST software style. Good luck with JAX-RS!