It is likely that a service will need to be handled by more than one resource. For example, in an order processing service best-practices suggests that each customer would be handled as a unique resource. Each order would also be handled as a unique resource.
Using the JAX-RS APIs, you would implement the customer resources and the order resources as
sub-resources. A sub-resource is a resource that is accessed through a root resource
class. They are defined by adding a @Path
annotation to a resource class' method.
Sub-resources can be implemented in one of two ways:
Sub-resource method—directly implements an HTTP verb for a sub-resource and is decorated with one of the annotations described in Specifying HTTP verbs.
Sub-resource locator—points to a class that implements the sub-resource.
Sub-resources are specified by decorating a method with the @Path
annotation. The URI of the sub-resource is constructed as follows:
Append the value of the sub-resource's
@Path
annotation to the value of the sub-resource's parent resource's@Path
annotation.The parent resource's
@Path
annotation maybe located on a method in a resource class that returns an object of the class containing the sub-resource.Repeat the previous step until the root resource is reached.
The assembled URI is appended to the base URI at which the service is deployed.
For example the URI of the sub-resource shown in Example 2.6 could be
.baseURI
/customerservice/order/12
Example 2.6. Order sub-resource
... @Path("/customerservice/") public class CustomerService { ... @Path("/orders/{orderId}/") @GET public Order getOrder(@PathParam("orderId") String orderId) { ... } }
A sub-resource method is decorated with both a @Path
annotation and
one of the HTTP verb annotations. The sub-resource method is directly responsible for handling a request
made on the resource using the specified HTTP verb.
Example 2.7 shows a resource class with three sub-resource methods:
getOrder()
handles HTTPGET
requests for resources whose URI matches/customerservice/orders/{orderId}/
.updateOrder()
handles HTTPPUT
requests for resources whose URI matches/customerservice/orders/{orderId}/
.newOrder()
handles HTTPPOST
requests for the resource at/customerservice/orders/
.
Example 2.7. Sub-resource methods
... @Path("/customerservice/") public class CustomerService { ... @Path("/orders/{orderId}/") @GET public Order getOrder(@PathParam("orderId") String orderId) { ... } @Path("/orders/{orderId}/") @PUT public Order updateOrder(@PathParam("orderId") String orderId, Order order) { ... } @Path("/orders/") @POST public Order newOrder(Order order) { ... } }
![]() | Note |
---|---|
Sub-resource methods with the same URI template are equivalent to resource class returned by a sub-resource locator. |
Sub-resource locators are not decorated with one of the HTTP verb annotations and do not directly handle are request on the sub-resource. Instead, a sub-resource locator returns an instance of a resource class that can handle the request.
In addition to not having an HTTP verb annotation, sub-resource locators also cannot have any entity parameters. All of the parameters used by a sub-resource locator method must use one of the annotations described in Passing Information into Resource Classes and Methods.
As shown in Example 2.8, sub-resource locator allows you to encapsulate a resource as a
reusable class instead of putting all of the methods into one super class. The processOrder()
method is a sub-resource locator. When a request is made on a URI matching the URI template
/orders/{orderId}/
it returns an instance of the Order
class. The
Order
class has methods that are decorated with HTTP verb annotations. A
PUT
request is handled by the updateOrder()
method.
Example 2.8. Sub-resource locator returning a specific class
... @Path("/customerservice/") public class CustomerService { ... @Path("/orders/{orderId}/") public Order processOrder(@PathParam("orderId") String orderId) { ... } ... } public class Order { ... @GET public Order getOrder(@PathParam("orderId") String orderId) { ... } @PUT public Order updateOrder(@PathParam("orderId") String orderId, Order order) { ... } }
Sub-resource locators are processed at runtime so that they can support polymorphism. The return value
of a sub-resource locator can be a generic Object
, an abstract class, or the top of a
class hierarchy. For example, if your service needed to process both PayPal orders and credit card orders, the
processOrder()
method's signature from Example 2.8 could
remain unchanged. You would simply need to implement two classes, ppOrder
and
ccOder
, that extended the Order
class. The implementation of
processOrder()
would instantiate the desired implementation of the sub-resource
based on what ever logic is required.