Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ protected static class ParamLocation {
private URI uri;
private HttpMethod method;
private LinkedHashMap<String, String> params;
private LinkedHashMap<String, List<String>> multipleValueParams;
private LinkedHashMap<String, String> headers;
private UsernamePasswordCredentials basicAuthCredentials;
private int paramLocation = ParamLocation.AUTO;
Expand All @@ -83,6 +84,7 @@ public RequestBuilder(HttpMethod method, URI uri) {
this.method = method;
this.uri = uri;
this.params = new LinkedHashMap<String, String>();
this.multipleValueParams = new LinkedHashMap<String, List<String>>();
this.headers = new LinkedHashMap<String, String>();
}

Expand Down Expand Up @@ -153,6 +155,45 @@ public RequestBuilder addParams(Map<String, String> 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<String> 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<String> 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<String, List<String>> listParams) {
putMultipleValueEntries(listParams, this.multipleValueParams);
return this;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add descriptions to the JavaDoc on these methods that explains the format that they are putting them in so that it's clear? Explain that it's using the KEY[]=... pattern so that it's explicit and clear.


/**
* Adds a header to this request with the given name and value.
* @param name The name of the header.
Expand Down Expand Up @@ -321,6 +362,12 @@ private void putEntries(Map<String, String> entries, Map<String, String> map) {
}
}

private void putMultipleValueEntries(Map<String, List<String>> entries, Map<String, List<String>> map) {
for (Entry<String, List<String>> entry : entries.entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
}

private void writeToStream(OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
long totalRead = 0;
Expand Down Expand Up @@ -357,15 +404,22 @@ private void writeToStream(OutputStream out) throws IOException {
}


private List<NameValuePair> getNameValuePairs(Map<String, String> map) {
private List<NameValuePair> getNameValuePairs(Map<String, String> map, Map<String, List<String>> listMap) {
List<NameValuePair> pairs = new LinkedList<NameValuePair>();
for (Entry<String, String> entry : map.entrySet()) {
pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
for (Entry<String, List<String>> entry : listMap.entrySet()) {
String key = String.format("%s[]", entry.getKey());
List<String> list = entry.getValue();
for (String value : list) {
pairs.add(new BasicNameValuePair(key, value));
}
}
return pairs;
}

private String getQueryString(Map<String, String> map) {
private String getQueryString(Map<String, String> map, Map<String, List<String>> listMap) {
StringBuilder queryBuilder = new StringBuilder();
boolean first = true;
for (Entry<String, String> entry : map.entrySet()) {
Expand All @@ -389,6 +443,29 @@ private String getQueryString(Map<String, String> map) {

}

for (Entry<String, List<String>> entry : listMap.entrySet()) {
// This will throw a NullPointerException if you call URLEncoder.encode(null).
// Instead caught & thrown with description above.
List<String> 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();
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
Expand Down