4

I need to generate an url with an array parameter, or looking like so:

?array_name[]=value1&array_name[]=value2

How to achieve this with Uri.Builder? The following code:

Uri.Builder builder = new Uri.Builder();
builder.appendQueryParameter("array[]", "one");
builder.appendQueryParameter("array[]", "another");
String result = builder.build().toString();

Gets me this output:

?array%5B%5D=one&array%5B%5D=another

In which square brackets are escaped.

How do I obtain the result that I want? I wouldn't like to ditch Uri.Builder altogether as the solution is already based on that class.

Konrad Morawski
  • 8,307
  • 7
  • 53
  • 91

2 Answers2

2

Not "all URLs are URIs". It depends on the interpretation of the RFC. For example in Java the URI parser does not like [ or ] and that's because the spec says "should not" and not "shall not"

This means that square brackets can't be straightly added in a URI (without encoding).

"[IPv6 host addresses] is the only place where square bracket characters are allowed in the URI syntax." If you use them in the right place, java.net.URI accepts them. new java.net.URI("foo://[1080:0:0:0:8:800:200C:417A]/a/b") succeeds for me in Java 1.7. "foo://example.com/a[b]" errors. This sounds in line with the RFC. The form new URI("http", "example.com", "/a/b[c]!$&'()*+", null, null) will %-encode the []. That java.net.URL accepts them elsewhere sounds like it's doing less validation

Do you really need to use array_name[] as name for your parameter? What exactly do you wish to achieve with ?array_name[]=value1&array_name[]=value2?

I think your best choice (and time saver choice) is to change your parameters name.

Your URI is constructed correctly. You encode [] to %5B%5D and then whoever receives your request should decode it. Still the answer to your specific question, if you can put [] into your URI is no.

Community
  • 1
  • 1
Narmer
  • 1,414
  • 7
  • 16
  • I guess? API documentation suggests that it is so. It would be consistent with the examples given in docs. `I think your best choice (and time saver choice) is to change your parameters name` - I have no control over the backend. – Konrad Morawski Aug 25 '14 at 14:46
  • The API that my app connects to. – Konrad Morawski Aug 25 '14 at 14:51
  • 1
    Well, in the back-end there should be a URI decoder which converts `%5B%5D` into `[]`, so the way you are building your URI is correct. If such decoder isn't present you should complain to whoever maintains the APIs. You simply can't put straightly `[]` into your URI. – Narmer Aug 25 '14 at 14:53
  • OK that does it then :) Thanks. – Konrad Morawski Aug 26 '14 at 06:38
0

appendQueryBuilder() (probably) encodes the string as per RFC 2396 and friends. Square braces are considered "reserved" characters and should be encoded if you ask for an encoded string.

Perhaps you could double-encode the param yourself, and use one of the setters that doesn't encoded chars, but rather assumes you have already encoded it?

EDIT

Wait, I don't really understand what this is supposed to do. Don't you want unique param key names? Shouldn't you be using an enumumeration or an array to hold the strings that are used to make the key names?

Maybe give an example of a "correct" URI and describe how it might be consumed by some code.

  • `and use one of the setters that doesn't encoded chars` - which setter would that be? – Konrad Morawski Aug 25 '14 at 14:41
  • I'd check the API docs for the version of the SDK you are using. Though I will add that double-encoding params is just a maintenance nightmare. I'm not in love with my answer. –  Aug 25 '14 at 14:42
  • I did before I asked the question: http://developer.android.com/reference/android/net/Uri.Builder.html - I can see nothing of help there – Konrad Morawski Aug 25 '14 at 14:42
  • 1
    `Maybe give an example of a "correct" URI and describe how it might be consumed by some code.` - the correct URI is in my question already. It's `?array_name[]=value1&array_name[]=value2`. The backend parses it as an array named `array_name` consisting of two values: `value1` and `value2`. – Konrad Morawski Aug 25 '14 at 14:49
  • Then decide what the name of the array is and use that as a param name. Then have the backend know that it needs to take "my_param_name" and treat it like an array (after an appropriate amount of input scrubbing!) –  Aug 25 '14 at 14:51
  • The name of the array has already been decided. The API is up and running, and used already (by an iOS app - I'm building the Android version). Of course the name is not exactly `array_name`, but I can't see why it would be relevant for the question – Konrad Morawski Aug 25 '14 at 14:54
  • If the backend is actually expecting "fnord[]" from the caller and using that to build a local array called "fnord", this is not the best URI based API. Your best answer is @Narmer's comment in the other thread. –  Aug 25 '14 at 14:59
  • ok, thanks - it looks like the API docs are a bit misleading in this regard. – Konrad Morawski Aug 26 '14 at 06:17