A root resource class is anchored in URI space using the @Path
annotation. The value of the annotation is a
relative URI path template whose base URI is provided by the deployment context.
The following code example is a very simple example of a root resource class using JAX-RS annotations:
import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; // The Java class will be hosted at the URI path "/helloworld" @Path("/helloworld") public class HelloWorldResource { // The Java method will process HTTP GET requests @GET // The Java method will produce content identified by the MIME Media // type "text/plain" @Produces("text/plain") public String getClichedMessage() { // Return some cliched textual content return "Hello World"; } }
@Target(value={TYPE,METHOD}) @Retention(value=RUNTIME) public @interface Path
Identifies the URI path that a resource class or class method will serve requests for.
Paths are relative. For an annotated class the base URI is the application path. For an annotated method the
base URI is the effective URI of the containing class. For the purposes of absolutizing a path against the
base URI , a leading '/
' in a path is ignored and base URIs are treated as if they ended in
'/
'. E.g.:
@Path("widgets") public class WidgetsResource { @GET String getList() {...} @GET @Path("{id}") String getWidget(@PathParam("id") String id) {...} }
In the above, if the application path is catalogue
and the application is deployed at
http://example.com/
, then GET requests for http://example.com/catalogue/widgets
will be
handled by the getList()
method while requests for
http://example.com/catalogue/widgets/nnn
(where nnn
is some value) will be handled
by the getWidget()
method. The same would apply if the value of either
@Path
annotation started with '/
'.
Session beans (Stateless or Singleton) can be implemented as JAX-RS resource or provider classes. EJB 3.1 and JAX-RS
work very well together thanks to JAX-RS flexibility in handling many kinds of resource classes, the EJB 3.1
no-interface view, and the ability to package enterprise beans directly in a .war
:
import javax.ejb.*; import javax.ws.rs.*; @Path("name") @Stateless public class NameService { @EJB private NameBean nameBean; @GET @Produces("text/plain") public String getHtml() { return "Hello " + nameBean.getName(); } @PUT @Consumes("text/plain") public void put(String content) { nameBean.setName(content); } }
The @Path
annotation's value is a relative URI path. In the HelloWorldResource
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}")
In this type of example, a user will be prompted to enter their name, and then a web service configured to respond
to requests to this URI path template will respond. For example, if the user entered their username as
"Mikalai
", the web service will respond to the following URL:
http://example.com/users/Mikalai
To obtain the value of the username variable the @PathParam
may be used on method parameter of a
request method, for example:
@Path("/users/{username}") public class UserResource { @GET @Produces("text/xml") public String getUser(@PathParam("username") String userName) { ... } }
If it is required that a user name must only consist of lower and upper case alpha-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 user names that begin with one
upper or lower case letter and zero or more alpha numeric characters and the underscore character. If a user
name does not match that a 404 (Not Found) response will occur.
A @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.
JAX-RS defines common HTTP methods using annotations: @GET
, @POST
,
@PUT
, @DELETE
, @HEAD
, and @OPTIONS
. Only public
methods may be exposed as resource methods. Listing below shows a customer resource exposing CRUD
methods. Note that the createCustomer
and updateCustomer
methods take an
InputStream
as a parameter which represents the HTTP request body:
@Path("/customers") public class CustomerResource { @GET public List<Customer> getListOfCustomers() { // ... } @POST @Consumes(MediaType.APPLICATION_XML) public Response createCustomer(InputStream is) { // ... } @PUT @Path("{customerId}") @Consumes(MediaType.APPLICATION_XML) public Response updateCustomer(@PathParam("customerId") String customerId, InputStream is) { // ... } @DELETE @Path("{customerId}") public void deleteCustomer(@PathParam("customerId") String customerId) { // ... } }
@Produces
The @Produces
annotation is used to specify the MIME media types of representations a resource can
produce and send back to the client. In this example, the Java method will produce representations identified
by the MIME media type "text/plain
".
@Produces
can be applied at both the class and method levels. Here's an example:
@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
@Produces
setting, and specifies that the method can produce HTML rather than plain text.
If a resource class is capable of producing more that one MIME media type then the resource method chosen will
correspond to the most acceptable media type as declared by the client. More specifically the Accept
header of the HTTP request declared what is most acceptable. For example if the Accept
header is:
Accept: text/plain
then the doGetAsPlainText
method will be invoked.
Alternatively if the Accept
header is:
Accept: text/plain; q=0.9, text/html
which declares that the client can accept media types of "text/plain
" and "text/html
" but
prefers the latter, then the doGetAsHtml
method will be invoked.
More than one media type may be declared in the same @Produces
declaration, for example:
@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.
The examples above refer explicitly to MIME media types for clarity. It is possible to refer to constant values,
which may reduce typographical errors, see the constant field values of MediaType
:
APPLICATION_ATOM_XML "application/atom+xml" APPLICATION_FORM_URLENCODED "application/x-www-form-urlencoded" APPLICATION_JSON "application/json" APPLICATION_OCTET_STREAM "application/octet-stream" APPLICATION_SVG_XML "application/svg+xml" APPLICATION_XHTML_XML "application/xhtml+xml" APPLICATION_XML "application/xml" MULTIPART_FORM_DATA "multipart/form-data" TEXT_HTML "text/html" TEXT_PLAIN "text/plain" TEXT_XML "text/xml" WILDCARD "*/*"
@Consumes
The @Consumes
annotation is used to specify the MIME media types of representations a resource can
consume that were sent by the client. The above example can be modified to set the cliched message as follows:
@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.
@Consumes
can be applied at both the class and method levels and more than one media type may be
declared in the same @Consumes
declaration.
JAX-RS standard entity parameter types
JAX-RS requires certain parameters to be supported for virtually any content type. The following table lists the supported content types:
Table 4.1. JAX-RS Standard Entity Parameter Types
Java Type | Content Type Supported |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Developers can use the previous Java types as entity parameters for requests and responses:
@Path("/example") public class RootResource { @GET @Produces("text/xml") public Response getInfo() { ... } @POST @Consumes("application/json") @Produces("application/json") public StreamingOutput createItem(InputStream requestBodyStream) { /* read the requestBodyStream like a normal input stream */ ... } }
Extracting Request Parameters
Parameters of a resource method may be annotated with parameter-based annotations to extract information from a request.
The following example presents the use @PathParam
to extract a path parameter (98342
) from the
path component of the request URL (http://java.boot.by/customers/98342
) that matched the path
declared in @Path
:
@Path("/customers") public class CustomerResource { @GET public Customer getCustomer(@PathParam("customerId") customerId) { // ... } }
The @QueryParam
annotation extracts the value of a URI query parameter. For example, the following code
allows you to extract the ZIP code parameter (220119
) out of the
http://java.boot.by/customers?zip=220119
URI:
@Path("/customers") public class CustomerResource { @GET public Customer getCustomerByZipCode(@QueryParam("zip") Long zip) { // ... } }
With all parameters annotations, you can add a @DefaultValue
annotation to define the default value for a
parameter you are expecting. The default value is used if the corresponding metadata is not present in the request.
In the following code, if the query parameter age is not in the request, the default value 50
is set:
@Path("/customers") public class CustomerResource { @GET public Response getCustomers(@DefaultValue("50") @QueryParam("age") int age) { // ... } }
If the @DefaultValue
is not used on conjuction with @QueryParam
and the query parameter is
not present in the request then value will be an empty collection for List
, Set
or
SortedSet
, null
for other object types, and the Java-defined default for primitive types.
The @PathParam
and the other parameter-based annotations, @MatrixParam
,
@HeaderParam
, @CookieParam
and @FormParam
obey the same rules as
@QueryParam
.
@MatrixParam
extracts information from URL path segments (; is used as a delimiter instead of ?). For
example, you will be able to extract the author's name (Mikalai
) out of this URL:
http://java.boot.by/products/books;author=Mikalai
.
@HeaderParam
extracts information from the HTTP headers. @CookieParam
extracts information
from the cookies declared in cookie related HTTP headers.
@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. 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:
@POST @Consumes("application/x-www-form-urlencoded") public void post(@FormParam("name") String name) { // Store the message }
If it is necessary to obtain a general map of parameter name to values then, for query and path parameters it is possible to do the following:
@GET public String get(@Context UriInfo ui) { MultivaluedMap<String, String> queryParams = ui.getQueryParameters(); MultivaluedMap<String, String> pathParams = ui.getPathParameters(); }
For header and cookie parameters the following:
@GET public String get(@Context HttpHeaders hh) { MultivaluedMap<String, String> headerParams = hh.getRequestHeaders(); Map<String, Cookie> pathParams = hh.getCookies(); }
In general @Context
can be used to obtain contextual Java types related to the request or response. For
form parameters it is possible to do the following:
@POST @Consumes("application/x-www-form-urlencoded") public void post(MultivaluedMap<String, String> formParams) { // Store the message }
blah-blah
blah-blah
A JAX-RS application is packaged as a Servlet in a .war
file. The Application
subclass,
resource classes, and providers are packaged in WEB-INF/classes
, required libraries are packaged
in WEB-INF/lib
. Included libraries may also contain resource classes and providers as desired.
The resources and providers that make up a JAX-RS application are configured via an application-supplied subclass of
Application
. An implementation may provide alternate mechanisms for locating resource classes and
providers (e.g. runtime class scanning) but use of javax.ws.rs.core.Application
is the only portable
means of configuration:
public abstract class Application { public abstract Set<Class<?>> getClasses(); public Set<Object>getSingletons(); }
The getClasses()
method returns a list of classes you want to deploy into the JAX-RS environment. They
can be @Path
annotated classes, in which case, you are specifying that you want to use the default
per-request component model. The getSingletons()
method returns actual instances that you
create yourself within the implementation of your Application
class. You use this method when you
want to have control over instance creation of your resource classes and providers.
JAX-RS provides the deployment agnostic abstract class Application
for declaring root resource and
provider classes, and root resource and provider singleton instances. A web service may extend this class to declare
root resource and provider classes. For example:
public class MyApplicaton extends Application { public Set<Class<?>> getClasses() { Set<Class<?>> s = new HashSet<Class<?>>(); s.add(by.boot.java.HelloWorldResource.class); return s; } }
Alternatively it is possible to reuse one of Jersey's implementations that scans for root resource and provider classes
given a classpath or a set of package names. Such classes are automatically added to the set of classes that are
returned by getClasses
. For example, the following scans for root resource and provider classes
in packages "by.boot.java
", "by.boot.rest
" and in any sub-packages of those two:
public class MyApplication extends PackagesResourceConfig { public MyApplication() { super("by.boot.java;by.boot.rest"); } }
For servlet deployments JAX-RS specifies that a class that implements Application
may be declared instead
of a servlet class in <servlet-class>
element of a web.xml
. This is supported for a web
container implementing Servlet 3.0 as follows:
<web-app> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>MyApplication</servlet-class> </servlet> <servlet-mapping> <servlet-name>Jersey Web Application</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping> .... </web-app>
If using Servlet 2.x then instead it is necessary to declare the Jersey specific servlet
(or any other JAX-RS implementation-supplied Servlet
class) and the application-supplied subclass of
Application
is identified using an init-param
with a param-name
of
javax.ws.rs.Application
as follows:
<web-app> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>MyApplication</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Jersey Web Application</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping> .... </web-app>
Alternatively a simpler approach is to let Jersey choose the PackagesResourceConfig
implementation
automatically by declaring the packages as follows:
<web-app> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>by.boot.java;by.boot.rest</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Jersey Web Application</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping> .... </web-app>
![]() |
![]() ![]() |