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 03:48:07 -0400

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.

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.