users@jsr311.java.net

Re: improvement of UriBuider.{query,matrix}Parameters and MultivaluedMap

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Wed, 18 Jun 2008 14:41:45 -0400

On Jun 18, 2008, at 10:11 AM, Stephan Koops wrote:
> IMO the UriBuilder could be improved for better useability, by
> adding some methods:
> • UriBuilder.replaceQueryParam(String, Object) // replace only one
> parameter
> • UriBuilder.replaceQueryParams(Map<String, Object>) // replace all
> parameters
> • UriBuilder.queryParams(Map<String, Object>) // adds the
> parameters to the current avaible params.
> and change one signature to
> • queryParam(String, Object)
> where - if the value for a key is a Collection, there are multiple
> parameters for the same key.
> The same methods should de added for matrix parameters.
>
How about just changing the existing method to

queryParam(String, Object...)

Each value Object gets converted to a String with toString. If you
have a collection you can write queryParam(name, values.toArray())

To address the substitution use case we could add:

replaceQueryParam(String, Object...)

Given that replaceQueryParams(null) removes any existing query
parameter I don't see the need to specify additional methods that
combine that functionality with the existing append functionality.

Maps are OK but what you really need is MultivaluedMap. However, I
don't want to make that a concrete API class.

> For the MultivaluedMap it seems useful to me to add:
> • public <A> A getFirst(K key, Class<A> convertTo)
> • public <A> A getFirst(K key, Class<A> convertTo, A defaultValue)
> • public <A> A getFirst(K key, A defaultValue); // if the
> defaultValue is directly the class to convert to (e.g. no subclass)
> it would work without the class parameter, I think.
> • public <A> List<A> get(K key, Class<A> convertTo)

We had this kind of generic method in our initial sketch of the API
but we removed them - I can't recall why now - Paul ?

Marc.



> Below I explain the reasons and details:
>
> As example I'm using a part of the query, that could be used by an
> issue tracker to generate a issue list:
> ...?...&issue_status
> =NEW&issue_status=STARTED&issue_status=REOPENED&page=1
>
> In this query it is useful to add an issue_status (with
> UriBuilder.queryParam), but it's also useful to replace the page
> number for a link, which is not easy possible yet. So I propose
> uriBuilder.replaceQueryParam("page", "2"); // all (or only the
> first?)
> This needs a lot of code, if you want to do it with UriInfo.
>
> It also seems useful to me to add UriBuilder.queryParams(Map<String,
> Object>) which adds the parameters, and
> UriBuilder.replaceQueryParams(Map<String, Object>), which replaces
> all parameters. This Map includes the MultivaluedMap, if a
> collection value is interpreted as multiple values for the given key.
> The same is useful for matrix parameters.
>
> IMO it is also useful to define a new Method in the MultivaluedMap:
> public <A> A getFirst(K key, Class<A> convertTo)
> This method is useful, if someone want to get the values as numbers,
> but also in other cases. The Class must contain a static
> valueOf(String) or a String constructor, as for the @*Param. Perhaps
> it is useful to allow optional as third parameter a default value of
> type A, if the given key is not available. The method must work with
> defaultValue == null.
> These methods could rethrow thrown runtime exceptions (including the
> WebApplicationException), and wrap a checked Exception as
> WebApplicationException. The best is, if the status is 404 or 400,
> as if a value for @*Param could not be converted.
>
> For analogy perhaps another method is useful:
> public <A> List<A> get(K key, Class<A> convertTo)
>
> These methods would allow
> uriBuilder.replaceQueryParam("page",
> uriInfo.getQueryParameters().getFirst("page", 1)+1);
> without the risk of a NPE, if no page parameter is given (but would
> not work, if the key "page" is given, but no value is given, which
> means "").
>
> According to the build methods it seems useful to me to allow an
> object as second parameter in {query,matrix}Param(String, String)
> instead of String, which allows e.g. ints. If the Object is a
> Collection, the elements could be used as multiple values for one
> parameter name.
>
> best regards
> Stephan

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