此内容没有您所选择的语言版本。
45.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:
- 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. - 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. - 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:
- 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.NoteA trailing slash (
/
) counts as a literal character. So /joefred/ will be preferred over /joefred. - 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.
- 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:
- Prefer resource methods over sub-resources.
- Prefer sub-resource methods over sub-resource locaters.
- 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("*/*")
. - Prefer methods that most closely match the content type of the request body entity.NoteThe content type of the request body entity is specified in the HTTP Content-Type property.
- Prefer methods that most closely match the content type accepted as a response.NoteThe 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 45.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 45.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.