users@jsr311.java.net

Re: Error in JAX-RS method finding algorithm?

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Mon, 11 Feb 2008 11:25:22 -0500

On Feb 11, 2008, at 10:25 AM, Barry Fitzgerald wrote:
>
> I think there is an error in the algorithm in the JAX-RS specs for
> choosing the resource method (see bullet 2. in section 2.6)
>
I'm not sure but you may be looking at an older version of the
specification. The latest is linked from http://jsr311.dev.java.net/.
However I think your comment is still relevant, more below.

> Consider the following scenario:
>
> I have a resource with 2 methods:
>
> @HttpMethod("GET")
> @UriTemplate("/users/{id}")
> @ProduceMime("text/xml")
> public Response getUser(@UriParam("id") String id) throws Exception
> { ....}
>
> @HttpMethod("GET")
> @UriTemplate("/users/{id}")
> @ProduceMime("application/json")
> public Response getUserJSON(@UriParam("id") String id) throws
> Exception { ....}
>
> If I then send a request to /users/24 with Accept headers of "text/
> xml, */*" one would expect the "text/xml" method to be invoked.
> However following the algorithm in the spec it is undefined which
> method should be invoked.
>
> More details:
>
> In the algorithm, both methods match the accept headers i.e. they
> are both added to the list of "matching resource methods" This list
> is then sorted using the consume mime type (not relevant in this
> case) and then by the produce mime. In this case it will compare
> "text/xml" against "application/json". As both are equally specific
> it is undefined which should be first.
>
> However surely as the "text/xml" method matches the accept header
> specifically it should always be returned first? See - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
> for further details
>
> One solution would be to change the algorithm to the following:
> • Sort the Accept header according to the W3 standards
> • Iterate through the accept header list. For each one:
> • Find all matching methods
> • If there is only one method return this and break out of the
> accept header loop
> • If there are multiple methods sort these methods using consume
> mime and produce mime. Then return the first.
> Therefore when accept header of "text/xml, text/*, */*" is sent in.
> Methods matching "text/html" are first searched for then "text/*"
> then "*/*". I think this would solve the problem.
>
You are describing the intended behavior, perhaps the spec could do
with some clarification. Section 2.5 step 3(b) says:

"Sort M using the media type of input data as the primary key and the
media type of output data
as the secondary key.

Sorting of media types follows the general rule: x/y < x/* < */*, i.e.
a method that explicitly lists one of the requested media types is
sorted before a method that lists */*. Quality parameter values are
also used such that x/y;q=1.0 < x/y;q=0.7."

The second paragraph is meant to cover your scenario. The getUser
method in your example explicitly lists "text/xml" from the accept
header so it would be sorted before the getUserJSON method.

Would the following modified first paragraph be clearer:

"Sort M as follows:
- The primary key is the media type of input data. Methods whose
ConsumeMime value most closely matches the media type of the request
are sorted first.
- The secondary key is the ProduceMime value. Methods whose value of
ProduceMime most closely match the value of the request accept header
are sorted first."

I will also add a reference to the appropriate section of the RFC to
the second paragraph.

Thanks,
Marc.

> This isn't some arbitrary obscure scenario.
>
> Looking at firefox's defaults it sends "text/xml,application/
> xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/
> png,*/*;q=0.5"
>
> Surely for a request from firefox I'd expect to get back one of the
> stated accepts not "application/widget" or "application/json"?
>
> Barry
>
>
>

---
Marc Hadley <marc.hadley at sun.com>
CTO Office, Sun Microsystems.