diff --git a/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java b/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java index 74de780..cc1a714 100644 --- a/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java +++ b/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java @@ -59,6 +59,7 @@ protected static class ParamLocation { private URI uri; private HttpMethod method; private LinkedHashMap params; + private LinkedHashMap> multipleValueParams; private LinkedHashMap headers; private UsernamePasswordCredentials basicAuthCredentials; private int paramLocation = ParamLocation.AUTO; @@ -83,6 +84,7 @@ public RequestBuilder(HttpMethod method, URI uri) { this.method = method; this.uri = uri; this.params = new LinkedHashMap(); + this.multipleValueParams = new LinkedHashMap>(); this.headers = new LinkedHashMap(); } @@ -153,6 +155,45 @@ public RequestBuilder addParams(Map params) { return this; } + /** + * Adds a single key, multiple value (KEY[]=1&KEY[]=2) parameter to this + * request. + * @param key The parameter key, without brackets. + * @param value The parameter value. + * @return This {@link RequestBuilder} object to allow for chaining of calls. + */ + public RequestBuilder addMultipleValueParam(String key, List value) { + multipleValueParams.put(key, value); + return this; + } + + /** + * Adds a single key, multiple value (KEY[]=1&KEY[]=2) parameter to the + * request if the value is not null. Note that this method will still add + * an empty list of values to the request. + * @param key The parameter key, without brackets. + * @param value The parameter value. + * @return This {@link RequestBuilder} object to allow for chaining of calls. + */ + public RequestBuilder addMultipleValueParamIfNotNull(String key, List value) { + if (value != null) { + addMultipleValueParam(key, value); + } + return this; + } + + /** + * Adds a {@link Map} of parameter single key, multiple value + * (KEY[]=1&KEY[]=2) parameter pairs as parameters of this request. + * Parameters are added in iteration order. + * @param params The {@link Map} of parameters. + * @return This {@link RequestBuilder} object to allow for chaining of calls. + */ + public RequestBuilder addMultipleValueParams(Map> listParams) { + putMultipleValueEntries(listParams, this.multipleValueParams); + return this; + } + /** * Adds a header to this request with the given name and value. * @param name The name of the header. @@ -321,6 +362,12 @@ private void putEntries(Map entries, Map map) { } } + private void putMultipleValueEntries(Map> entries, Map> map) { + for (Entry> entry : entries.entrySet()) { + map.put(entry.getKey(), entry.getValue()); + } + } + private void writeToStream(OutputStream out) throws IOException { byte[] buffer = new byte[1024]; long totalRead = 0; @@ -357,15 +404,22 @@ private void writeToStream(OutputStream out) throws IOException { } - private List getNameValuePairs(Map map) { + private List getNameValuePairs(Map map, Map> listMap) { List pairs = new LinkedList(); for (Entry entry : map.entrySet()) { pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } + for (Entry> entry : listMap.entrySet()) { + String key = String.format("%s[]", entry.getKey()); + List list = entry.getValue(); + for (String value : list) { + pairs.add(new BasicNameValuePair(key, value)); + } + } return pairs; } - private String getQueryString(Map map) { + private String getQueryString(Map map, Map> listMap) { StringBuilder queryBuilder = new StringBuilder(); boolean first = true; for (Entry entry : map.entrySet()) { @@ -389,6 +443,29 @@ private String getQueryString(Map map) { } + for (Entry> entry : listMap.entrySet()) { + // This will throw a NullPointerException if you call URLEncoder.encode(null). + // Instead caught & thrown with description above. + List list = entry.getValue(); + if (list == null) { + // Can't be more specific without jeopardizing security. + throw new NullPointerException("Malformed Request. RequestBuilder entry " + + "has null value for key "+entry.getKey()+" on URI "+this.uri+"."); + } + + String key = entry.getKey(); + for (String value : list) { + if (!first) { + queryBuilder.append("&"); + } + queryBuilder.append(key); + queryBuilder.append("[]="); + queryBuilder.append(URLEncoder.encode(value)); + + first = false; + } + } + return queryBuilder.toString(); } @@ -400,8 +477,8 @@ protected String getUrl() { String url = uri.toString(); // If we should set params in the url and we have params to set, do so - if ((getParamLocationResolved() == ParamLocation.URL) && (params.size() > 0)) { - String queryString = "?" + getQueryString(params); + if ((getParamLocationResolved() == ParamLocation.URL) && ((params.size() > 0) || (multipleValueParams.size() > 0))) { + String queryString = "?" + getQueryString(params, multipleValueParams); url = String.format("%s%s", uri, queryString); } @@ -435,7 +512,7 @@ public HttpURLConnection getConnection() { // If we have params and this is a post, we need to do output // but they will be written later - if (params.size() > 0 && (getParamLocationResolved() == ParamLocation.BODY)) { + if (((params.size() > 0) || (multipleValueParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { connection.setDoOutput(true); } @@ -469,9 +546,9 @@ public HttpURLConnection getConnection() { */ public void onConnected(HttpURLConnection connection) { // If we have params and this is a put, we need to write them here - if (params.size() > 0 && (getParamLocationResolved() == ParamLocation.BODY)) { + if (((params.size() > 0) || (multipleValueParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { // Convert the params to a query string, and write it to the body. - String query = getQueryString(params); + String query = getQueryString(params, multipleValueParams); try { connection.getOutputStream().write(query.getBytes()); } catch (IOException e) { @@ -518,9 +595,9 @@ public HttpUriRequest getRequest() { // If we have parameters and this is a post, we need to add // the parameters to the body - if (params.size() > 0 && (getParamLocationResolved() == ParamLocation.BODY)) { + if (((params.size() > 0) || (multipleValueParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { try { - ((HttpEntityEnclosingRequest)request).setEntity(new UrlEncodedFormEntity(getNameValuePairs(params))); + ((HttpEntityEnclosingRequest)request).setEntity(new UrlEncodedFormEntity(getNameValuePairs(params, multipleValueParams))); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); }