30
30
import java .io .InputStream ;
31
31
import java .io .UnsupportedEncodingException ;
32
32
import java .util .ArrayList ;
33
+ import java .util .Collections ;
34
+ import java .util .HashSet ;
33
35
import java .util .LinkedList ;
34
36
import java .util .List ;
35
37
import java .util .Map ;
38
+ import java .util .Set ;
36
39
import java .util .concurrent .ConcurrentHashMap ;
37
40
38
41
/**
49
52
* params.put("profile_picture", new File("pic.jpg")); // Upload a File
50
53
* params.put("profile_picture2", someInputStream); // Upload an InputStream
51
54
* params.put("profile_picture3", new ByteArrayInputStream(someBytes)); // Upload some bytes
55
+ *
56
+ * Map<String, String> map = new HashMap<String, String>();
57
+ * map.put("first_name", "James");
58
+ * map.put("last_name", "Smith");
59
+ * params.put("user", map); // url params: "user[first_name]=James&user[last_name]=Smith"
60
+ *
61
+ * Set<String> set = new HashSet<String>(); // unordered collection
62
+ * set.add("music");
63
+ * set.add("art");
64
+ * params.put("like", set); // url params: "like=music&like=art"
65
+ *
66
+ * List<String> list = new ArrayList<String>(); // Ordered collection
67
+ * list.add("Java");
68
+ * list.add("C");
69
+ * params.put("languages", list); // url params: "languages[]=Java&languages[]=C"
70
+ *
71
+ * String[] colors = { "blue", "yellow" }; // Ordered collection
72
+ * params.put("colors", colors); // url params: "colors[]=blue&colors[]=yellow"
73
+ *
74
+ * List<Map<String, String>> listOfMaps = new ArrayList<Map<String, String>>();
75
+ * Map<String, String> user1 = new HashMap<String, String>();
76
+ * user1.put("age", "30");
77
+ * user1.put("gender", "male");
78
+ * Map<String, String> user2 = new HashMap<String, String>();
79
+ * user2.put("age", "25");
80
+ * user2.put("gender", "female");
81
+ * listOfMaps.add(user1);
82
+ * listOfMaps.add(user2);
83
+ * params.put("users", listOfMaps); // url params: "users[][age]=30&users[][gender]=male&users[][age]=25&users[][gender]=female"
52
84
*
53
85
* AsyncHttpClient client = new AsyncHttpClient();
54
86
* client.post("http://myendpoint.com", params, responseHandler);
@@ -61,7 +93,7 @@ public class RequestParams {
61
93
protected ConcurrentHashMap <String , String > urlParams ;
62
94
protected ConcurrentHashMap <String , StreamWrapper > streamParams ;
63
95
protected ConcurrentHashMap <String , FileWrapper > fileParams ;
64
- protected ConcurrentHashMap <String , ArrayList < String >> urlParamsWithArray ;
96
+ protected ConcurrentHashMap <String , Object > urlParamsWithObjects ;
65
97
66
98
/**
67
99
* Constructs a new empty <code>RequestParams</code> instance.
@@ -154,18 +186,6 @@ public void put(String key, File file, String contentType) throws FileNotFoundEx
154
186
}
155
187
}
156
188
157
- /**
158
- * Adds param with more than one value.
159
- *
160
- * @param key the key name for the new param.
161
- * @param values is the ArrayList with values for the param.
162
- */
163
- public void put (String key , ArrayList <String > values ) {
164
- if (key != null && values != null ) {
165
- urlParamsWithArray .put (key , values );
166
- }
167
- }
168
-
169
189
/**
170
190
* Adds an input stream to the request.
171
191
*
@@ -201,6 +221,38 @@ public void put(String key, InputStream stream, String name, String contentType)
201
221
}
202
222
}
203
223
224
+ /**
225
+ * Adds param with non-string value (e.g. Map, List, Set).
226
+ * @param key the key name for the new param.
227
+ * @param value the non-string value object for the new param.
228
+ */
229
+ public void put (String key , Object value ) {
230
+ if (key != null && value != null ) {
231
+ urlParamsWithObjects .put (key , value );
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Adds string value to param which can have more than one value.
237
+ * @param key the key name for the param, either existing or new.
238
+ * @param value the value string for the new param.
239
+ */
240
+ public void add (String key , String value ) {
241
+ if (key != null && value != null ) {
242
+ Object params = urlParamsWithObjects .get (key );
243
+ if (params == null ) {
244
+ // Backward compatible, which will result in "k=v1&k=v2&k=v3"
245
+ params = new HashSet <String >();
246
+ this .put (key , params );
247
+ }
248
+ if (params instanceof List ) {
249
+ ((List <Object >) params ).add (value );
250
+ } else if (params instanceof Set ) {
251
+ ((Set <Object >) params ).add (value );
252
+ }
253
+ }
254
+ }
255
+
204
256
/**
205
257
* Removes a parameter from the request.
206
258
*
@@ -210,7 +262,7 @@ public void remove(String key) {
210
262
urlParams .remove (key );
211
263
streamParams .remove (key );
212
264
fileParams .remove (key );
213
- urlParamsWithArray .remove (key );
265
+ urlParamsWithObjects .remove (key );
214
266
}
215
267
216
268
@ Override
@@ -243,18 +295,14 @@ public String toString() {
243
295
result .append ("FILE" );
244
296
}
245
297
246
- for (ConcurrentHashMap .Entry <String , ArrayList <String >> entry : urlParamsWithArray .entrySet ()) {
298
+ List <BasicNameValuePair > params = getParamsList (null , urlParamsWithObjects );
299
+ for (BasicNameValuePair kv : params ) {
247
300
if (result .length () > 0 )
248
301
result .append ("&" );
249
-
250
- ArrayList <String > values = entry .getValue ();
251
- for (int i = 0 ; i < values .size (); i ++) {
252
- if (i != 0 )
253
- result .append ("&" );
254
- result .append (entry .getKey ());
255
- result .append ("=" );
256
- result .append (values .get (i ));
257
- }
302
+
303
+ result .append (kv .getName ());
304
+ result .append ("=" );
305
+ result .append (kv .getValue ());
258
306
}
259
307
260
308
return result .toString ();
@@ -291,13 +339,10 @@ private HttpEntity createMultipartEntity(AsyncHttpResponseHandler progressHandle
291
339
entity .addPart (entry .getKey (), entry .getValue ());
292
340
}
293
341
294
- // Add dupe params
295
- for (ConcurrentHashMap .Entry <String , ArrayList <String >> entry : urlParamsWithArray
296
- .entrySet ()) {
297
- ArrayList <String > values = entry .getValue ();
298
- for (String value : values ) {
299
- entity .addPart (entry .getKey (), value );
300
- }
342
+ // Add non-string params
343
+ List <BasicNameValuePair > params = getParamsList (null , urlParamsWithObjects );
344
+ for (BasicNameValuePair kv : params ) {
345
+ entity .addPart (kv .getName (), kv .getValue ());
301
346
}
302
347
303
348
// Add stream params
@@ -322,7 +367,7 @@ private void init() {
322
367
urlParams = new ConcurrentHashMap <String , String >();
323
368
streamParams = new ConcurrentHashMap <String , StreamWrapper >();
324
369
fileParams = new ConcurrentHashMap <String , FileWrapper >();
325
- urlParamsWithArray = new ConcurrentHashMap <String , ArrayList < String > >();
370
+ urlParamsWithObjects = new ConcurrentHashMap <String , Object >();
326
371
}
327
372
328
373
protected List <BasicNameValuePair > getParamsList () {
@@ -332,16 +377,46 @@ protected List<BasicNameValuePair> getParamsList() {
332
377
lparams .add (new BasicNameValuePair (entry .getKey (), entry .getValue ()));
333
378
}
334
379
335
- for (ConcurrentHashMap .Entry <String , ArrayList <String >> entry : urlParamsWithArray .entrySet ()) {
336
- ArrayList <String > values = entry .getValue ();
337
- for (String value : values ) {
338
- lparams .add (new BasicNameValuePair (entry .getKey (), value ));
339
- }
340
- }
380
+ lparams .addAll (getParamsList (null , urlParamsWithObjects ));
341
381
342
382
return lparams ;
343
383
}
344
384
385
+ private List <BasicNameValuePair > getParamsList (String key , Object value ) {
386
+ List <BasicNameValuePair > params = new LinkedList <BasicNameValuePair >();
387
+ if (value instanceof Map ) {
388
+ Map <String , Object > map = (Map <String , Object >) value ;
389
+ List <String > list = new ArrayList <String >(map .keySet ());
390
+ // Ensure consistent ordering in query string
391
+ Collections .sort (list );
392
+ for (String nestedKey : list ) {
393
+ Object nestedValue = map .get (nestedKey );
394
+ if (nestedValue != null ) {
395
+ params .addAll (getParamsList (key == null ? nestedKey : String .format ("%s[%s]" , key , nestedKey ),
396
+ nestedValue ));
397
+ }
398
+ }
399
+ } else if (value instanceof List ) {
400
+ List <Object > list = (List <Object >) value ;
401
+ for (Object nestedValue : list ) {
402
+ params .addAll (getParamsList (String .format ("%s[]" , key ), nestedValue ));
403
+ }
404
+ } else if (value instanceof Object []) {
405
+ Object [] array = (Object []) value ;
406
+ for (Object nestedValue : array ) {
407
+ params .addAll (getParamsList (String .format ("%s[]" , key ), nestedValue ));
408
+ }
409
+ } else if (value instanceof Set ) {
410
+ Set <Object > set = (Set <Object >) value ;
411
+ for (Object nestedValue : set ) {
412
+ params .addAll (getParamsList (key , nestedValue ));
413
+ }
414
+ } else if (value instanceof String ) {
415
+ params .add (new BasicNameValuePair (key , (String ) value ));
416
+ }
417
+ return params ;
418
+ }
419
+
345
420
protected String getParamString () {
346
421
return URLEncodedUtils .format (getParamsList (), HTTP .UTF_8 );
347
422
}
@@ -367,4 +442,4 @@ public StreamWrapper(InputStream inputStream, String name, String contentType) {
367
442
this .contentType = contentType ;
368
443
}
369
444
}
370
- }
445
+ }
0 commit comments