users@jsr311.java.net

Re: JAX-RS: UriBuilder.fromResource treats templates differently

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Mon, 07 Jul 2008 05:09:32 -0400

On Jul 7, 2008, at 3:48 AM, Marc Hadley wrote:

> If we go with adding support for regexs for parameters I was
> thinking we might support optional validation of template values in
> UriBuilder. While not perfect you would at least get an error when
> you try to build the URI in the example below.
>
Actually we already require some validation in UriBuilder.build. If a
parameter value contains illegal characters and encode is false you
should get a IllegalArgumentException. Currently '/' isn't classed as
an illegal character but we could make it so if limited==true for the
template parameter.

Marc.

> The issue though is that we are then diverging from the likely path
> of the URI template specification which is what gives me pause on
> the whole regex idea.
>
> Marc.
>
> On Jul 6, 2008, at 7:19 PM, Manger, James H wrote:
>
>> A @Path value can be used to 1) match a request to a resource, and
>> 2) to build a URI.
>> The two uses are inconsistent in how they treat {…} placeholders.
>> UriBuilder effectively treats all placeholders as unlimited even
>> when they were limited during matching (disallowing /).
>>
>> Consider this code:
>>
>> @Path(“{bar}”)
>> public class FooResource
>> {
>> @GET
>> public URI doStuff(@PathParam(“bar”) String s)
>> {
>> return UriBuilder.fromResource(FooResource.class).build(s);
>> }
>> }
>>
>> The URI “123%2Fabc” matches this resource.
>> However, UriBuilder returns “123/abc”, which does NOT match the
>> resource –
>> despite being built with fromResource(). YIKES, that was surprising!
>>
>> This problem could be fixed *in this example* by annotating
>> doStuff’s parameter with @Encoded and telling UriBuilder not to
>> encode:
>> public URI doStuff(@PathParam(“bar”) @Encoded String s)
>> {
>> return
>> UriBuilder.fromResource(FooResource.class).encode(false).build(s);
>> }
>> This is not a general solution however. It is still a problem when
>> the parameter values passed to UriBuilder.build(…) come from some
>> other source. The UriBuilder.build() caller has to do their own
>> encoding, and the caller has to know what encoding to do (eg is /
>> allowed? how about ampersands or semicolons? …), which will depend
>> on the template. This seems to defeat the purpose of templates
>> somewhat.
>>
>>
>> UriBuilder is not consistent with draft-gregorio-uritemplate-03 –
>> nor is it likely to be consistent with any final spec. A specific
>> design choice in draft-gregorio-uritemplate-03 is to prevent any
>> <reserved> chars coming from a parameter value. All URI structure
>> (ie <reserved> chars) is controlled by the template author, not the
>> party providing the parameter values. <reserved> chars in parameter
>> values are always %-escaped. UriBuilder, in contrast, %-escapes
>> much less (just ? and # in paths, I think; not sure what elsewhere).
>> The 18 <reserved> chars are : / ? # [ ] @ ! $ & ‘ ( ) * + , ; =
>>
>>
>> SOLUTION
>>
>> I don’t have a nice, quick, easy solution.
>>
>> My preference would be for UriBuilder to support an Internet URI
>> template spec once such a thing is finalized.
>> That point is not close enough for JAX-RS so I think UriBuilder
>> should only try to support the most basic templates that will
>> (almost) certainly be compatible with a future URI template spec.
>>
>> My suggestion:
>> • UriBuilder should accept templates with {name} placeholders.
>> • Each placeholder is replaced with the corresponding parameter
>> value after %-escaping all non-<unreserved> characters in that
>> value (or replaced by an empty string if the parameter is not
>> defined). UriBuilder.isEncoded() does NOT apply to parameters
>> passed to UriBuilder.build() – they always get encoded.
>> • The name in {name} should be a valid Java identifier (or an
>> identifier as defined in Unicode annex #31 “Identifier and Pattern
>> syntax” http://www.unicode.org/reports/tr31/ ). Future versions of
>> JAX-RS may give special meaning to other names, though
>> implementations of this version of JAX-RS must treat them all the
>> same.
>> Now the hard part, what to do with unlimited (or :regex)
>> placeholders from @Path values. Three options (from most preferred
>> to least):
>> • Scrap the UriBuilder.fromResource(Class) and
>> UriBuilder.path(Class/Method) methods – admitting that parsing and
>> building (though related) are too awkward to unite in a single
>> syntax. Code can still call
>>
>> UriBuilder
>> .fromPath(FooResource.class.getAnnotation(Path.class).value());
>> if it really wants.
>> • UriBuilder explicitly states that when it accepts @Path values,
>> it totally ignores the limited=false attribute (or:regex component).
>> • Something more complicated.
>>
>> A URI template spec is likely to allow a placeholder to expand into
>> multiple path segments (like an unlimited @Path placeholder) – but
>> only if each segment is passed as a separate string (eg { “123”,
>> “abc” } -> “123/abc”; while “123/abc” -> “123%2Fabc”).
>> Consequently, the following method would be useful:
>> UriBuilder.build(MultivaluedMap<String,Object> values)
>> It would be a bit strange to define such a method before UriBuilder
>> supports templates sophisticated enough to indicate how multiple
>> values are handled. Would it cause any hassles if adding this
>> method was deferred to a future version of the spec (given that
>> UriBuilder is an abstract class, not an interface)?
>>
>> James Manger
>>
>
> ---
> Marc Hadley <marc.hadley at sun.com>
> CTO Office, Sun Microsystems.
>
>
>
> ---------------------------------------------------------------------
> 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.