users@jsr311.java.net

Re: Selecting between method candidates

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Mon, 12 May 2008 14:01:53 -0400

On May 9, 2008, at 10:02 AM, Sergey Beryozkin wrote:
>
> I've read the latest spec and I did a bit of testing with CXF with
> regard to this specific scenario...
> I'd like to start again and explain how I see the algorithm working...
> Here's the sample class :
>
> @Path("/{a}")
> public class FooClass {
>
> @GET
> @Path("/")
> public Bars listBars() {...}
>
> @GET
> @PATH("/{e}")
> public Bar readBar() {...}
> }
> I've just added the @Path("/") to the listBars(). Lets assume that
> both methods support the same set of Produce/Consume mime types.
>
> Request is : GET /1/
>
> So we start from 3.7.1, selecting a resource class.

That's 3.7.2 in the latest version of the spec.

> When '/1/' is matched against a reg expression produced from @Path("/
> {a}"), the match is ok and the final matching group is '/'.
>
> Next we move to 3.7.2.a

3.7.2, bullet 2a

> which says that if U is either null (which would be the case if we
> has '/1' request) or '/' as in our case, we move on to 3.7.3.
>
3.7.2, bullet 3

> This is a bit confusing to me as we haven't even done yet any match
> against resource methods of FooClass - shouldn't that be done at
> least once ?
>
The algorithm doesn't support splitting methods for the same resource
across multiple classes, so e.g. you can't do something like:

@Path("foo/{a}")
public class Foo1 {
   @GET
   String getSomething() {...}
}

@Path("foo/{a}")
public class Foo2 {
   @PUT
   String putSomething(...) {...}
}

> In CXF, the 'at least' once match is actually done, seems like it
> does not break the algorithm, but I'm not sure. So during this match
> '/' is successfully matched against both listBars and readBars due
> with the help from corresponding reg expressions.
>
> Here I'd like to ask : am I correct in assuming that the 'at least
> once' run through 3.7.2 should be attempted in this case ?
>
I'm not exactly sure what you mean by an "at least one" match but the
resource method designator (@GET etc) doesn't appear in the algorithm
until 3.7.2, bullet 3 (after you've identified the object to handle
the request).

> If yes, then it seems to me that the only criterias for choosing
> between listBars and readBar are those specified in 3.7.2.f and they
> all actually seem equal to me (source is the same - both are
> resource methods, numebr of capturing groups is the same - none,
> except perhaps for a number of literals after substitution is also
> the same - 1 for readBar, 0 for - listBar)
>
> Is it correct or not ?
>
> If not then all the selection needs to be done in 3.7.f.3 and I can
> not see there how listBar should be selected instead of readBar.
>
Yes, that's true. There does seem to be an edge case for @Path("/"),
probably a result of our special-casing of '/' as the path segment
separator. I'm not really sure what to do about it though. One thing
we could do is to change the regexp expansion for a path parameter
from (.*?) to (.+?), if we did that then @Path("{foo}") would no
longer match an empty path segment. so the two @Path you have in your
example wouldn't both match /1/. Another approach would be programmatic:

@Path("/{a}")
public class FooClass {

  @GET
  public Bars listBars() {...}

  @GET
  @PATH("/{e}")
  public Bar readBar(@PathParam("e") String e) {
    if (e==null || e.length()==0)
      throw new WebApplicationException(Response.seeOther(a).build());
    ...
  }
}

Marc.

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