dev@jsr311.java.net

Re: JSR311: Re: Error in JAX-RS method finding algorithm?

From: Bill Burke <bburke_at_redhat.com>
Date: Mon, 11 Feb 2008 13:22:07 -0500

Still doesn't make sense to me. The spec nor these emails make it clear
to me what we want. Do we want a method picked that most closely
matches the preferred Accept header? Or do we want one that most
closely matches the @ConsumeMime of a method? For example:



method1: @ConsumeMime("text/*") @ProduceMime("text/html")
method2: @ConsumeMime("text/xml") @ProduceMime("text/json")

Accept: text/html, */*
content-type: text/xml


ACCEPT HEADER TAKES PRECEDENCE:

Sort by consume:

method2 "text/html"
method1 "text/*"

Then sort by accepts/produce:

method1 "text/html"
methdo2 "text/json"


Method1 would be picked in the scenario even though the content-type
matches method2 better. This gives precedence to the Accept header. As
a method that does not more distinctly match the content-type will be
chosen if there is a method that more distinctly matches the accept
type. Is this the intended matching algorithm?


OR

Does the statement "most closely matches" omit method1 from the first
sort list because it has wildcards? If so, we need a clearer algorithm.
  Something like:

@ConsumeMime TAKES PRECEDENCE:


So, I'm saying the algorithm should be:

1. Find all methods that could match based on content-type and accept
headers along with produce/consume metadata
2. Sort list based on @ConsumeMime and RFC
3. Remove methods that are not as descriptive
4. Sort accepts header list base on RFC

foreach accept header
   foreach remainingSortedMethod
      if method supports accept header, thats your pick

This approach gives precedence to matching based on the content-type and
@ConsumeMime metadata.



Marc Hadley wrote:
> 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.
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_jsr311.dev.java.net
> For additional commands, e-mail: dev-help_at_jsr311.dev.java.net
>
>

-- 
Bill Burke
JBoss, a division of Red Hat
http://bill.burkecentral.com