users@jsr311.java.net

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

From: Stephan Koops <Stephan.Koops_at_web.de>
Date: Wed, 18 Jun 2008 16:11:38 +0200

Hi,

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.

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)

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