users@jsr311.java.net

JAX-RS: UriBuilder.buildFromMap(MultivaluedMap)

From: Manger, James H <James.H.Manger_at_team.telstra.com>
Date: Mon, 21 Jul 2008 11:28:26 +1000

>> P.S. I would also like URI buildMap(MultivaluedMap<String,?> values).

> Why ?

To support limited and unlimited placeholders.


I agree with draft-gregorio-uritemplate-03.txt<http://tools.ietf.org/html/draft-gregorio-uritemplate-03> that a parameter value (as passed to UriBuilder.build*) should provide content to a URI, but not structure. That is, the UriBuilder.build* methods should %-escape any non-unreserved characters in a parameter value. In the following example, the resulting URI would always have a single path segment, regardless of any ‘/’ chars in the value passed to build().

  UriBuilder.fromPath("{foo}").build("abc/123/def") -> "abc%2F123%2Fdef"

However, @Path templates can have “limited” and “unlimited” placeholders. %-escaping all non-unreserved chars provides good support for limited placeholder. build(MultivaluedMap) would provide good support for unlimited placeholders – multiple segments could be created by passing multiple values for the placeholder. In the following example, “foo” is mapped to 2 values so 2 path segments are created.

  MultivaluedMap<String,String> values = …;
  values.add("foo", "abc/123");
  values.add("foo", "def");
  UriBuilder.fromResource( @Path(value="{foo}", limited=false)).buildFromMap(values) -> "abc%2F123/def"

Possible javadoc text:

  public abstract URI buildFromMap(MultivaluedMap<String,?> values)

  Build a URI, replacing any placeholders with the values from the supplied map.
  Each value is converted to a String using its toString method
  then any non-unreserved characters are %-escaped (as per quote(String)).
  For an unlimited placeholder (a trailing placeholder in an @Path annotation
  with limited=false) multiple values are concatenated separated by ‘/’ characters.
  For other (limited) placeholders multiple values are concatenated without
  any separator.

  For example:
    @Path("{foo}")
    public class Resource1 {…}

    @Path(value="{foo}", limited=false)
    public class Resource2 {…}

    MultivaluedMap<String,String> values = …;
    values.add("foo", "abc/123");
    values.add("foo", "def");
    URI u1 = UriBuilder.fromResource(Resource1.class).buildFromMap(values);
    // builds "abc%2F123def"
    URI u2 = UriBuilder.fromResource(Resource2.class).buildFromMap(values);
    // builds "abc%2F123/def"


buildFromMap(MultivaluedMap) would also be useful for suppling multiple values for a query parameter – once the URI template syntax supports that. For instance, a template “stats?op=average{&n=number*}” could build “stats?op=average&n=23&n=3&n=98”.

P.S. It would be convenient to have a concrete implementation of MultivaluedMap in the API. Perhaps MultivaluedHashMap<K,V>.

James Manger