From 1b26ef3534aae0b7466a90b0d75e86355bee6538 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Wed, 4 Jun 2014 18:31:11 -0400 Subject: [PATCH 1/2] Add support for HTTP list parameters --- .../raizlabs/net/requests/RequestBuilder.java | 92 +++++++++++++++++-- 1 file changed, 83 insertions(+), 9 deletions(-) diff --git a/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java b/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java index 74de780..d978588 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> listParams; 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.listParams = new LinkedHashMap>(); this.headers = new LinkedHashMap(); } @@ -153,6 +155,42 @@ public RequestBuilder addParams(Map params) { return this; } + /** + * Adds a 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 addListParam(String key, List value) { + listParams.put(key, value); + return this; + } + + /** + * Adds a 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 addListParamIfNotNull(String key, List value) { + if (value != null) { + addListParam(key, value); + } + return this; + } + + /** + * Adds a {@link Map} of parameter key value 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 addListParams(Map> listParams) { + putListEntries(listParams, this.listParams); + return this; + } + /** * Adds a header to this request with the given name and value. * @param name The name of the header. @@ -321,6 +359,12 @@ private void putEntries(Map entries, Map map) { } } + private void putListEntries(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 +401,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 +440,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 +474,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) || (listParams.size() > 0))) { + String queryString = "?" + getQueryString(params, listParams); url = String.format("%s%s", uri, queryString); } @@ -435,7 +509,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) || (listParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { connection.setDoOutput(true); } @@ -469,9 +543,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) || (listParams.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, listParams); try { connection.getOutputStream().write(query.getBytes()); } catch (IOException e) { @@ -518,9 +592,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) || (listParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { try { - ((HttpEntityEnclosingRequest)request).setEntity(new UrlEncodedFormEntity(getNameValuePairs(params))); + ((HttpEntityEnclosingRequest)request).setEntity(new UrlEncodedFormEntity(getNameValuePairs(params, listParams))); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } From f8cbfbaba8fb17a44dbabd7903a2b38e75b73abd Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Mon, 14 Jul 2014 18:10:02 -0400 Subject: [PATCH 2/2] Renaming listParam to multipleValueParam --- .../raizlabs/net/requests/RequestBuilder.java | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java b/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java index d978588..cc1a714 100644 --- a/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java +++ b/WebServiceManager/src/com/raizlabs/net/requests/RequestBuilder.java @@ -59,7 +59,7 @@ protected static class ParamLocation { private URI uri; private HttpMethod method; private LinkedHashMap params; - private LinkedHashMap> listParams; + private LinkedHashMap> multipleValueParams; private LinkedHashMap headers; private UsernamePasswordCredentials basicAuthCredentials; private int paramLocation = ParamLocation.AUTO; @@ -84,7 +84,7 @@ public RequestBuilder(HttpMethod method, URI uri) { this.method = method; this.uri = uri; this.params = new LinkedHashMap(); - this.listParams = new LinkedHashMap>(); + this.multipleValueParams = new LinkedHashMap>(); this.headers = new LinkedHashMap(); } @@ -156,38 +156,41 @@ public RequestBuilder addParams(Map params) { } /** - * Adds a parameter to this request. + * 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 addListParam(String key, List value) { - listParams.put(key, value); + public RequestBuilder addMultipleValueParam(String key, List value) { + multipleValueParams.put(key, value); return this; } /** - * Adds a 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. + * 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 addListParamIfNotNull(String key, List value) { + public RequestBuilder addMultipleValueParamIfNotNull(String key, List value) { if (value != null) { - addListParam(key, value); + addMultipleValueParam(key, value); } return this; } /** - * Adds a {@link Map} of parameter key value pairs as parameters of this - * request. Parameters are added in iteration order. + * 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 addListParams(Map> listParams) { - putListEntries(listParams, this.listParams); + public RequestBuilder addMultipleValueParams(Map> listParams) { + putMultipleValueEntries(listParams, this.multipleValueParams); return this; } @@ -359,7 +362,7 @@ private void putEntries(Map entries, Map map) { } } - private void putListEntries(Map> entries, Map> map) { + private void putMultipleValueEntries(Map> entries, Map> map) { for (Entry> entry : entries.entrySet()) { map.put(entry.getKey(), entry.getValue()); } @@ -474,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) || (listParams.size() > 0))) { - String queryString = "?" + getQueryString(params, listParams); + if ((getParamLocationResolved() == ParamLocation.URL) && ((params.size() > 0) || (multipleValueParams.size() > 0))) { + String queryString = "?" + getQueryString(params, multipleValueParams); url = String.format("%s%s", uri, queryString); } @@ -509,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) || (listParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { + if (((params.size() > 0) || (multipleValueParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { connection.setDoOutput(true); } @@ -543,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) || (listParams.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, listParams); + String query = getQueryString(params, multipleValueParams); try { connection.getOutputStream().write(query.getBytes()); } catch (IOException e) { @@ -592,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) || (listParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { + if (((params.size() > 0) || (multipleValueParams.size() > 0)) && (getParamLocationResolved() == ParamLocation.BODY)) { try { - ((HttpEntityEnclosingRequest)request).setEntity(new UrlEncodedFormEntity(getNameValuePairs(params, listParams))); + ((HttpEntityEnclosingRequest)request).setEntity(new UrlEncodedFormEntity(getNameValuePairs(params, multipleValueParams))); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); }