users@jsr311.java.net

Re: JAX-RS: _at_Path limited=false templates: (?!/).+(?<!/)

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Wed, 02 Jul 2008 12:28:58 -0400

Funny, Paul and I were just discussing the exact same idea ! I'm not
exactly sold on this yet but lets explore the idea to see if we end up
somewhere good.

> I understand James's usecase, but I don't like his solution. I
> never liked the 'limited' annotation attribute and thought we should
> expand on @Path expressions instead. I propose supporting regular
> expressions instead. Here's my idea:
>
> "{}" denotes a PathParam, expression, or both:
>
> "{" [ path_param ] ":" expression "}" |
> "{" path_param "}"
>
> The ":" denotes that there is an expression to be matched. If the
> ":" is preceded by a path_param, then fill that path_param with that
> value.
>
> For example:
>
> 1. /foo/{param}/blah -> "/foo/([^/])+"
> 2. /foo/{param: .*}/image.jpg -> "/foo/(.*)?/image.jpg"
> 3. /foo/{:.*}/image.jpg -> "/foo/.*/image.jpg"
>
>
> #1 is an example of a path param with no expression
> #2 is an example of a path param that matches a particular expression
> #3 is an example of just an expression with no path param
>
So essentially if its a named template var then you turn whatever
follows the ':' into a capturing group. I notice in your example you
follow the capturing group with '?' - why ? Is there a usecase for
allowing the user to specify qualifiers for a capturing group ?

>
> We support regular expressions in JAX-RS 1.0. If we want to support
> different expressions down the road we can either:
>
> * create a new @Path annotation
> @W3cPath

This is probably the most straightforward.

Marc.

>
> * Create an expression annotation that tells how to match the @Path
> expression
>
> @Path("/-pre(43233)hello")
> @RFC3322PathExpresions
>
> * Or add an attribute to @Path (I don't like this approach).
>
>
> Stephan Koops wrote:
>> Hi James,
>> I think it is a more common case, that you have a fix start of the
>> path and the different ends of the path to be matched. But perhaps
>> we could support both with a new attribute, analogue to limited.
>> Let's see, what the others say.
>> BTW: You could handle the file extensions the the extension
>> mapping, and use the http content negotiation, or leave the
>> extension out. IMO you should not hardcode the file extensions.
>> best regards
>> Stephan
>> Manger, James H schrieb:
>>> A @Path template can have a placeholder for:
>>> 1) A single path segment (or part of one); or
>>> 2) Everything remaining in the path.
>>>
>>> {name} at the end of a @Path value with limited=false gives the
>>> 2nd option;
>>> {name} in any other circumstance gives the 1st option.
>>>
>>> These are the only two options, but I am not confident that they
>>> will be sufficient.
>>>
>>> I suspect many web apps might use a variable-depth hierarchy in
>>> the *middle* of their URIs. Below are some made up examples, none
>>> of which are valid in JAX-RS 0.9:
>>>
>>> 1. A genealogy site with any number of ancestors;
>>> http://example.net/genealogy/alice/bob/chris/photo.jpg
>>> http://example.net/genealogy/alice/bob/tree.json
>>> http://example.net/genealogy/alice/bob/dave/details.html
>>> => @Path(value="genealogy/{ancestors}/photo.jpg", limited=false)
>>> @Path(value="genealogy/{ancestors}/tree.json", limited=false)
>>>
>>> 2. A Java source code repository;
>>> http://example.net/java/java/lang/Integer/methods.json
>>> http://example.net/java/javax/ws/rs/core/Request/methods.xml
>>> http://example.net/java/javax/ws/rs/core/Request/dependencies.xml
>>> => @Path(value="java/{class}/methods.{format}", limited=false)
>>>
>>>
>>> There are two hassles:
>>> 1. limited=false should apply to specific {...} placeholders,
>>> not a whole path that can have many placeholders;
>>> 2. You cannot have anything after a limited=false placeholder.
>>>
>>>
>>> I suggest that when limited=false, {name} should (greedily) match
>>> at least 1 char, and not start or end with a '/'. This is a change
>>> from matching the whole remaining path (except an optional final
>>> '/'). It allows literal characters after the placeholder.
>>> When limited=false replace {name} with:
>>> (?!/).+(?<!/)
>>>
>>> I also suggest limited=false should apply to the *FIRST*
>>> placeholder, not the last. Better still, there could be two types
>>> of placeholder --
>>> say {name} and {name*} -- for limited and unlimited placeholders
>>> respectively.
>>>
>>> Applying limited=false to the *FIRST* placeholder still allows
>>> code that wants an earlier limited placeholder to use two @Path
>>> annotations (eg on a class then method). The reverse is harder.
>>> That is, when limited=false applies to the *LAST* placeholder it
>>> is not currently possible (and still harder with mods) to allow
>>> code that wants a later limited placeholder. Using a subsequent
>>> @Path does not really work as the whole path has already been
>>> gobbled up.
>>>
>>> Example: http://example.net/cafes/us/california/sanfran/city/east/map.png
>>>
>>> @Path("{country}")
>>> class Abc {
>>> @Path(value="{location}/map.png", limited=false)
>>> public Image getMap(...)
>>> @Path(value="{location}/description.html", limited=false)
>>> public String getWebpage(...)
>>> }
>>>
>>>
>>> Proposed replacement for
>>> 3.7.3 Converting URI Templates to Regular expressions. The changes
>>> are to points 3, 4 & 5.
>>>
>>>
>>> "The function R(A) converts a URI path template annotation A into
>>> a regular expression as follows:
>>> 1. If A:encode = true, URI encode the template, ignoring URI
>>> template variable specifications.
>>> 2. Escape any regular expression characters in the URI template,
>>> again ignoring URI template variable
>>> specifications.
>>> 3. Replace all limited placeholders with the regular expression
>>> ‘([ˆ/]+?)’.
>>> 4. Replace all unlimited placeholders with the regular expression
>>> ‘(?!/).+(?<!/)’.
>>> 5. If the resulting string ends with ‘/’ append ‘(.+)?’, otherwise
>>> append ‘(?:/(.+))?’
>>> Note that the above renders the name of template variables
>>> irrelevant for template matching purposes. However,
>>> implementations will need to retain template variable names in
>>> order to facilitate the extraction of
>>> template variable values via @PathParam or
>>> UriInfo.getTemplateParameters."
>>>
>>>
>>> [The final capturing group does not start with '/' so §3.7.2 2(a)
>>> would need to be adjusted from "If U is null or '/'" to "If U is
>>> null".]
>>>
>>>
>>> P.S. In the current §3.7.3 "Converting URI Templates to Regular
>>> Expressions" the result is undefined if limited=false, but the
>>> "final URI template variable" (placeholder) is not the "last thing
>>> in the URI template".
>>>
>>> James Manger
>>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jsr311.dev.java.net
>> For additional commands, e-mail: users-help_at_jsr311.dev.java.net
>
> --
> Bill Burke
> JBoss, a division of Red Hat
> http://bill.burkecentral.com
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jsr311.dev.java.net
> For additional commands, e-mail: users-help_at_jsr311.dev.java.net
>

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