此内容没有您所选择的语言版本。

Chapter 46. Creating Resources


Abstract

In RESTful Web services all requests are handled by resources. The JAX-RS APIs implement resources as a Java class. A resource class is a Java class that is annotated with one, or more, JAX-RS annotations. The core of a RESTful Web service implemented using JAX-RS is a root resource class. The root resource class is the entry point to the resource tree exposed by a service. It may handle all requests itself, or it may provide access to sub-resources that handle requests.

46.1. Introduction

Overview

RESTful Web services implemented using JAX-RS APIs provide responses as representations of a resource implemented by Java classes. A resource class is a class that uses JAX-RS annotations to implement a resource. For most RESTful Web services, there is a collection of resources that need to be accessed. The resource class' annotations provide information such as the URI of the resources and which HTTP verb each operation handles.

Types of resources

The JAX-RS APIs allow you to create two basic types of resources:

  • A Section 46.3, “Root resource classes” is the entry point to a service’s resource tree. It is decorated with the @Path annotation to define the base URI for the resources in the service.
  • Section 46.5, “Working with sub-resources” are accessed through the root resource. They are implemented by methods that are decorated with the @Path annotation. A sub-resource’s @Path annotation defines a URI relative to the base URI of a root resource.

Example

Example 46.1, “Simple resource class” shows a simple resource class.

Example 46.1. Simple resource class

package demo.jaxrs.server;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path("/customerservice")
public class CustomerService
{
  public CustomerService()
  {
  }

  @GET
  public Customer getCustomer(@QueryParam("id") String id)
  {
    ...
  }

  ...
}

Two items make the class defined in Example 46.1, “Simple resource class” a resource class:

The @Path annotation specifies the base URI for the resource.

The @GET annotation specifies that the method implements the HTTP GET method for the resource.

46.2. Basic JAX-RS annotations

Overview

The most basic pieces of information required by a RESTful Web service implementation are:

  • the URI of the service’s resources
  • how the class' methods are mapped to the HTTP verbs

JAX-RS defines a set of annotations that provide this basic information. All resource classes must have at least one of these annotations.

Setting the path

The @Path annotation specifies the URI of a resource. The annotation is defined by the javax.ws.rs.Path interface and it can be used to decorate either a resource class or a resource method. It takes a string value as its only parameter. The string value is a URI template that specifies the location of an implemented resource.

The URI template specifies a relative location for the resource. As shown in Example 46.2, “URI template syntax”, the template can contain the following:

  • unprocessed path components
  • parameter identifiers surrounded by { }

    Note

    Parameter identifiers can include regular expressions to alter the default path processing.

Example 46.2. URI template syntax

@Path("resourceName/{param1}/../{paramN}")

For example, the URI template widgets/{color}/{number} would map to widgets/blue/12. The value of the color parameter is assigned to blue. The value of the number parameter is assigned 12.

How the URI template is mapped to a complete URI depends on what the @Path annotation is decorating. If it is placed on a root resource class, the URI template is the root URI of all resources in the tree and it is appended directly to the URI at which the service is published. If the annotation decorates a sub-resource, it is relative to the root resource URI.

Specifying HTTP verbs

JAX-RS uses five annotations for specifying the HTTP verb that will be used for a method:

  • javax.ws.rs.DELETE specifies that the method maps to a DELETE.
  • javax.ws.rs.GET specifies that the method maps to a GET.
  • javax.ws.rs.POST specifies that the method maps to a POST.
  • javax.ws.rs.PUT specifies that the method maps to a PUT.
  • javax.ws.rs.HEAD specifies that the method maps to a HEAD.

When you map your methods to HTTP verbs, you must ensure that the mapping makes sense. For example, if you map a method that is intended to submit a purchase order, you would map it to a PUT or a POST. Mapping it to a GET or a DELETE would result in unpredictable behavior.

46.3. Root resource classes

Overview

A root resource class is the entry point into a JAX-RS implemented RESTful Web service. It is decorated with a @Path that specifies the root URI of the resources implemented by the service. Its methods either directly implement operations on the resource or provide access to sub-resources.

Requirements

In order for a class to be a root resource class it must meet the following criteria:

  • The class must be decorated with the @Path annotation.

    The specified path is the root URI for all of the resources implemented by the service. If the root resource class specifies that its path is widgets and one of its methods implements the GET verb, then a GET on widgets invokes that method. If a sub-resource specifies that its URI is {id}, then the full URI template for the sub-resource is widgets/{id} and it will handle requests made to URIs like widgets/12 and widgets/42.

  • The class must have a public constructor for the runtime to invoke.

    The runtime must be able to provide values for all of the constructor’s parameters. The constructor’s parameters can include parameters decorated with the JAX-RS parameter annotations. For more information on the parameter annotations see Chapter 47, Passing Information into Resource Classes and Methods.

  • At least one of the classes methods must either be decorated with an HTTP verb annotation or the @Path annotation.

Example

Example 46.3, “Root resource class” shows a root resource class that provides access to a sub-resource.

Example 46.3. Root resource class

package demo.jaxrs.server;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/customerservice/")
public class CustomerService
{
  public CustomerService()
  {
    ...
  }

  @GET
  public Customer getCustomer(@QueryParam("id") String id)
  {
    ...
  }

  @DELETE
  public Response deleteCustomer(@QueryParam("id") String id)
  {
    ...
  }

  @PUT
  public Response updateCustomer(Customer customer)
  {
    ...
  }

  @POST
  public Response addCustomer(Customer customer)
  {
    ...
  }

  @Path("/orders/{orderId}/")
  public Order getOrder(@PathParam("orderId") String orderId)
  {
    ...
  }

}

The class in Example 46.3, “Root resource class” meets all of the requirements for a root resource class.

The class is decorated with the @Path annotation. The root URI for the resources exposed by the service is customerservice.

The class has a public constructor. In this case the no argument constructor is used for simplicity.

The class implements each of the four HTTP verbs for the resource.

The class also provides access to a sub-resource through the getOrder() method. The URI for the sub-resource, as specified using the the @Path annotation, is customerservice/order/id. The sub-resource is implemented by the Order class.

For more information on implementing sub-resources see Section 46.5, “Working with sub-resources”.

46.4. Working with resource methods

Overview

Resource methods are annotated using JAX-RS annotations. They have one of the HTTP method annotation specifying the types of requests that the method processes. JAX-RS places several constraints on resource methods.

General constraints

All resource methods must meet the following conditions:

Parameters

Resource method parameters take two forms:

  • entity parameters—Entity parameters are not annotated. Their value is mapped from the request entity body. An entity parameter can be of any type for which your application has an entity provider. Typically they are JAXB objects.

    Important

    A resource method can have only one entity parameter.

    For more information on entity providers see Chapter 51, Entity Support.

  • annotated parameters—Annotated parameters use one of the JAX-RS annotations that specify how the value of the parameter is mapped from the request. Typically, the value of the parameter is mapped from portions of the request URI.

    For more information about using the JAX-RS annotations for mapping request data to method parameters see Chapter 47, Passing Information into Resource Classes and Methods.

Example 46.4, “Resource method with a valid parameter list” shows a resource method with a valid parameter list.

Example 46.4. Resource method with a valid parameter list

@POST
@Path("disaster/monster/giant/{id}")
public void addDaikaiju(Kaiju kaiju,
                        @PathParam("id") String id)
{
  ...
}

Example 46.5, “Resource method with an invalid parameter list” shows a resource method with an invalid parameter list. It has two parameters that are not annotated.

Example 46.5. Resource method with an invalid parameter list

@POST
@Path("disaster/monster/giant/")
public void addDaikaiju(Kaiju kaiju,
                        String id)
{
  ...
}

Return values

Resource methods can return one of the following:

All resource methods return an HTTP status code to the requester. When the return type of the method is void or the value being returned is null, the resource method sets the HTTP status code to 204. When the resource method returns any value other than null, it sets the HTTP status code to 200.

46.5. Working with sub-resources

Overview

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:

Specifying a sub-resource

Sub-resources are specified by decorating a method with the @Path annotation. The URI of the sub-resource is constructed as follows:

  1. 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.

  2. Repeat the previous step until the root resource is reached.
  3. 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 46.6, “Order sub-resource” could be baseURI/customerservice/order/12.

Example 46.6. Order sub-resource

...
@Path("/customerservice/")
public class CustomerService
{
  ...
  @Path("/orders/{orderId}/")
  @GET
  public Order getOrder(@PathParam("orderId") String orderId)
  {
    ...
  }
}

Sub-resource methods

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 46.7, “Sub-resource methods” shows a resource class with three sub-resource methods:

  • getOrder() handles HTTP GET requests for resources whose URI matches /customerservice/orders/{orderId}/.
  • updateOrder() handles HTTP PUT requests for resources whose URI matches /customerservice/orders/{orderId}/.
  • newOrder() handles HTTP POST requests for the resource at /customerservice/orders/.

Example 46.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

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 Chapter 47, Passing Information into Resource Classes and Methods.

As shown in Example 46.8, “Sub-resource locator returning a specific class”, 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 46.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 46.8, “Sub-resource locator returning a specific class” 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.

46.6. Resource selection method

Overview

It is possible for a given URI to map to one or more resource methods. For example the URI customerservice/12/ma could match the templates @Path("customerservice/{id}") or @Path("customerservice/{id}/{state}"). JAX-RS specifies a detailed algorithm for matching a resource method to a request. The algorithm compares the normalized URI, the HTTP verb, and the media types of the request and response entities to the annotations on the resource classes.

The basic selection algorithm

The JAX-RS selection algorithm is broken down into three stages:

  1. Determine the root resource class.

    The request URI is matched against all of the classes decorated with the @Path annotation. The classes whose @Path annotation matches the request URI are determined.

    If the value of the resource class' @Path annotation matches the entire request URI, the class' methods are used as input into the third stage.

  2. Determine the object will handle the request.

    If the request URI is longer than the value of the selected class' @Path annotation, the values of the resource methods' @Path annotations are used to look for a sub-resource that can process the request.

    If one or more sub-resource methods match the request URI, these methods are used as input for the third stage.

    If the only matches for the request URI are sub-resource locaters, the resource methods of the object created by the sub-resource locater to match the request URI. This stage is repeated until a sub-resource method matches the request URI.

  3. Select the resource method that will handle the request.

    The resource method whose HTTP verb annotation matches the HTTP verb in the request. In addition, the selected resource method must accept the media type of the request entity body and be capable of producing a response that conforms to the media type(s) specified in the request.

Selecting from multiple resource classes

The first two stages of the selection algorithm determine the resource that will handle the request. In some cases the resource is implemented by a resource class. In other cases, it is implemented by one or more sub-resources that use the same URI template. When there are multiple resources that match a request URI, resource classes are preferred over sub-resources.

If more than one resource still matches the request URI after sorting between resource classes and sub-resources, the following criteria are used to select a single resource:

  1. Prefer the resource with the most literal characters in its URI template.

    Literal characters are characters that are not part of a template variable. For example, /widgets/{id}/{color} has ten literal characters and /widgets/1/{color} has eleven literal characters. So, the request URI /widgets/1/red would be matched to the resource with /widgets/1/{color} as its URI template.

    Note

    A trailing slash (/) counts as a literal character. So /joefred/ will be preferred over /joefred.

  2. Prefer the resource with the most variables in its URI template.

    The request URI /widgets/30/green could match both /widgets/{id}/{color} and /widgets/{amount}/. However, the resource with the URI template /widgets/{id}/{color} will be selected because it has two variables.

  3. Prefer the resource with the most variables containing regular expressions.

    The request URI /widgets/30/green could match both /widgets/{number}/{color} and /widgets/{id:.}/{color}*. However, the resource with the URI template */widgets/{id:.}/{color} will be selected because it has a variable containing a regular expression.

Selecting from multiple resource methods

In many cases, selecting a resource that matches the request URI results in a single resource method that can process the request. The method is determined by matching the HTTP verb specified in the request with a resource method’s HTTP verb annotation. In addition to having the appropriate HTTP verb annotation, the selected method must also be able to handle the request entity included in the request and be able to produce the proper type of response specified in the request’s metadata.

Note

The type of request entity a resource method can handle is specified by the @Consumes annotation. The type of responses a resource method can produce are specified using the @Produces annotation.

When selecting a resource produces multiple methods that can handle a request the following criteria is used to select the resource method that will handle the request:

  1. Prefer resource methods over sub-resources.
  2. Prefer sub-resource methods over sub-resource locaters.
  3. Prefer methods that use the most specific values in the @Consumes annotation and the @Produces annotation.

    For example, a method that has the annotation @Consumes("text/xml") would be preferred over a method that has the annotation @Consumes("text/*"). Both methods would be preferred over a method without an @Consumes annotation or the annotation @Consumes("\*/*").

  4. Prefer methods that most closely match the content type of the request body entity.

    Note

    The content type of the request body entity is specified in the HTTP Content-Type property.

  5. Prefer methods that most closely match the content type accepted as a response.

    Note

    The content types accepted as a response are specified in the HTTP Accept property.

Customizing the selection process

In some cases, developers have reported the algorithm being somewhat restrictive in the way multiple resource classes are selected. For example, if a given resource class has been matched and if this class has no matching resource method, then the algorithm stops executing. It never checks the remaining matching resource classes.

Apache CXF provides the org.apache.cxf.jaxrs.ext.ResourceComparator interface which can be used to customize how the runtime handles multiple matching resource classes. The ResourceComparator interface, shown in Example 46.9, “Interface for customizing resource selection”, has to methods that need to be implemented. One compares two resource classes and the other compares two resource methods.

Example 46.9. Interface for customizing resource selection

package org.apache.cxf.jaxrs.ext;

import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.message.Message;

public interface ResourceComparator
{
  int compare(ClassResourceInfo cri1,
              ClassResourceInfo cri2,
              Message message);

  int compare(OperationResourceInfo oper1,
              OperationResourceInfo oper2,
              Message message);
}

Custom implementations select between the two resources as follows:

  • Return 1 if the first parameter is a better match than the second parameter
  • Return -1 if the second parameter is a better match than the first parameter

If 0 is returned then the runtime will proceed with the default selection algorithm

You register a custom ResourceComparator implementation by adding a resourceComparator child to the service’s jaxrs:server element.

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.