Is there a widely-used Java library that does something like what dojo.objectToQuery() does? E.g. (assuming the use of HttpCore's HttpParams object, but any key-value mapping will do):
HttpParams params = new BasicHttpParams()
.setParameter("foo", "bar")
.setParameter("thud", "grunt");
UnknownLibrary.toQueryString(params);
should yield "foo=bar&thud=grunt".
I know it's not hard to write but it seems like it should have already been written. I just can't find it.
Why reinvent the wheel? Apache HttpClient has URLEncodedUtils:
List<BasicNameValuePair> params = Arrays.asList(new BasicNameValuePair("\\%^ &=@#:", "\\%^ &=@#:"));
String query = URLEncodedUtils.format(params, "UTF-8");
I ended up writing my own. It can be called like
URIUtils.withQuery(uri, "param1", "value1", "param2", "value2");
which isn't so bad.
/**
* Concatenates <code>uri</code> with a query string generated from
* <code>params</code>.
*
* @param uri the base URI
* @param params a <code>Map</code> of key/value pairs
* @return a new <code>URI</code>
*/
public static URI withQuery(URI uri, Map<String, String> params) {
StringBuilder query = new StringBuilder();
char separator = '?';
for (Entry<String, String> param : params.entrySet()) {
query.append(separator);
separator = '&';
try {
query.append(URLEncoder.encode(param.getKey(), "UTF-8"));
if (!StringUtils.isEmpty(param.getValue())) {
query.append('=');
query.append(URLEncoder.encode(param.getValue(), "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return URI.create(uri.toString() + query.toString());
}
/**
* Concatenates <code>uri</code> with a query string generated from
* <code>params</code>. The members of <code>params</code> will be
* interpreted as {key1, val1, key2, val2}. Empty values can be given
* as <code>""</code> or <code>null</code>.
*
* @param uri the base URI
* @param params the key/value pairs in sequence
* @return a new <code>URI</code>
*/
public static URI withQuery(URI uri, String... params) {
Map<String, String> map = new LinkedHashMap<String, String>();
for (int i = 0; i < params.length; i += 2) {
String key = params[i];
String val = i + 1 < params.length ? params[i + 1] : "";
map.put(key, val);
}
return withQuery(uri, map);
}
You don't really need a library for that. I didn't find one in HttpCore either so I wrote something like this,
public String toString() {
StringBuilder sb = new StringBuilder(baseUrl);
char separator;
if (baseUrl.indexOf('?') > 0)
separator = '&';
else
separator = '?';
for (Parameter p : parameters) {
sb.append(separator);
try {
sb.append(URLEncoder.encode(p.name, "UTF-8"));
if (p.value != null) {
sb.append('=');
sb.append(URLEncoder.encode(p.value, "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
// Not really possible, throw unchecked exception
throw new IllegalStateException("No UTF-8");
}
separator = '&';
}
return sb.toString();
}
If you have JAX-RS there is javax.ws.rs.core.UriBuilder; other than that you should primarily be aware of URLEncoder and URLDecoder which will at least encode the pieces of the parameter list.
There are plenty of libraries that can help you with URI building (don't reinvent the wheel). Here is one to get you started:
org.springframework:spring-web:4.2.5.RELEASE
import org.springframework.web.util.UriComponentsBuilder;
...
return UriComponentsBuilder.fromUriString(url).queryParam(key, value).build().toUri();
See also: GIST > URI Builder Tests