Convert map to query string

Transforming a Map to a query string is straight forward due to the natural name/value pair structure. This example will show various libraries can convert the map into a query string in java. Two things to be aware of, first is that the snippets don't focus on encoding the urls and second is that it is possible to have multiple query parameters with the same name. Since Maps naturally don't support duplicate values you may need to look for alternative if your use case requires it. A comparable examples shows how to transform a map to a query string using groovy.

Setup

Map<String, String> mapToConvert;

@Before
public void setup() {

    mapToConvert = new HashMap<String, String>();
    mapToConvert.put("end-date", "2014-11-26");
    mapToConvert.put("itemsPerPage", String.valueOf(25));
}

Jersey

Jersey serves as a JAX-RS (JSR 311 & JSR 339) reference implementation and there isn't a nice method that accepts a Map. Due to this limitation we can iterate over a hashmap with a for loop passing the key and value into the builder.queryParam.

@Test
public void construct_uri_jersey () {

    UriBuilder builder = UriBuilder
            .fromPath("www.leveluplunch.com")
            .scheme("http");

    for (Entry<String, String> entry : mapToConvert.entrySet()) {
        builder.queryParam(entry.getKey(), entry.getValue());
    }

    URI uri = builder.build();

    assertEquals(
            "http:/www.leveluplunch.com?end-date=2014-11-26&itemsPerPage=25",
            uri.toString());
}

Google Guava

An issues exists in guava's backlog to include a new, useful URI class which might accept a Map as part of a builder or utility. Until then we can convert map to string using a ampersand as a separator using guava. As part of the query string spec we will need to include a question mark when the string below would be combined with the URL itself.

@Test
public void convert_map_to_querystring_guava() {

    String mapJoined = Joiner.on("&").withKeyValueSeparator("=")
            .join(mapToConvert);

    assertEquals("end-date=2014-11-26&itemsPerPage=25", mapJoined);
}

Spring Framework

Converting the Map to a spring MultiValueMap which is an extension of a map that allows keys to be associated to multiple values. Passing the instance created to UriComponentsBuilder.queryParams will allow us to build a new query string from a map.

@Test
public void convert_map_to_uri_spring() {

    MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
    for (Entry<String, String> entry : mapToConvert.entrySet()) {
        params.add(entry.getKey(), entry.getValue());
    }

    UriComponents uriComponents = UriComponentsBuilder.newInstance()
            .scheme("http").host("www.leveluplunch.com")
            .queryParams(params).build();

    assertEquals(
            "http://www.leveluplunch.com?end-date=2014-11-26&itemsPerPage=25",
            uriComponents.toUriString());
}

Apache Commons

Converting our Map of query string parameters to NameValuePair, which is similar in a sense to the spring snippet above, will allow us to pass it into the URIBuilder.setParameters.

@Test
public void contruct_uri_parameters_apache () throws URISyntaxException {

    List<NameValuePair> queryParams = new ArrayList<NameValuePair>();
    for (Entry<String, String> entry : mapToConvert.entrySet()) {
        queryParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
    }

    URIBuilder builder = new URIBuilder()
            .setScheme("http")
            .setHost("www.leveluplunch.com")
            .setParameters(queryParams);

    URI uri = builder.build();

    assertEquals(
            "http://www.leveluplunch.com?end-date=2014-11-26&itemsPerPage=25",
            uri.toString());
}