Added methods for managing uri query parameters

Change-Id: Ic98c1bd159740dd4d895889079f9f2abae4fc2b9
This commit is contained in:
Ben Dodson
2010-08-18 18:23:18 -07:00
parent 363e035f5f
commit 58a345936d
3 changed files with 255 additions and 67 deletions

View File

@@ -105431,6 +105431,17 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
<method name="getQueryParameterNames"
return="java.util.Set&lt;java.lang.String&gt;"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="getQueryParameters"
return="java.util.List&lt;java.lang.String&gt;"
abstract="false"
@@ -105677,6 +105688,17 @@
visibility="public"
>
</method>
<method name="clearQuery"
return="android.net.Uri.Builder"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="encodedAuthority"
return="android.net.Uri.Builder"
abstract="false"

View File

@@ -28,8 +28,10 @@ import java.net.URLEncoder;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.RandomAccess;
import java.util.Set;
/**
* Immutable URI reference. A URI reference includes a URI and a fragment, the
@@ -47,7 +49,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
/*
This class aims to do as little up front work as possible. To accomplish
that, we vary the implementation dependending on what the user passes in.
that, we vary the implementation depending on what the user passes in.
For example, we have one implementation if the user passes in a
URI string (StringUri) and another if the user passes in the
individual components (OpaqueUri).
@@ -1261,6 +1263,8 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* <p>An opaque URI follows this pattern:
* {@code <scheme>:<opaque part>#<fragment>}
*
* <p>Use {@link Uri#buildUpon()} to obtain a builder representing an existing URI.
*/
public static final class Builder {
@@ -1446,6 +1450,13 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
return this;
}
/**
* Clears the the previously set query.
*/
public Builder clearQuery() {
return query((Part) null);
}
/**
* Constructs a Uri with the current attributes.
*
@@ -1490,6 +1501,45 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
}
/**
* Returns a set of the unique names of all query parameters. Iterating
* over the set will return the names in order of their first occurrence.
*
* @throws UnsupportedOperationException if this isn't a hierarchical URI
*
* @return a set of decoded names
*/
public Set<String> getQueryParameterNames() {
if (isOpaque()) {
throw new UnsupportedOperationException(NOT_HIERARCHICAL);
}
String query = getEncodedQuery();
if (query == null) {
return Collections.emptySet();
}
Set<String> names = new LinkedHashSet<String>();
int start = 0;
do {
int next = query.indexOf('&', start);
int end = (next == -1) ? query.length() : next;
int separator = query.indexOf('=', start);
if (separator > end || separator == -1) {
separator = end;
}
String name = query.substring(start, separator);
names.add(decode(name));
// Move start to end of name.
start = end + 1;
} while (start < query.length());
return Collections.unmodifiableSet(names);
}
/**
* Searches the query string for parameter values with the given key.
*
@@ -1497,13 +1547,15 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @throws UnsupportedOperationException if this isn't a hierarchical URI
* @throws NullPointerException if key is null
*
* @return a list of decoded values
*/
public List<String> getQueryParameters(String key) {
if (isOpaque()) {
throw new UnsupportedOperationException(NOT_HIERARCHICAL);
}
if (key == null) {
throw new NullPointerException("key");
}
String query = getEncodedQuery();
if (query == null) {
@@ -1517,39 +1569,34 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
throw new AssertionError(e);
}
// Prepend query with "&" making the first parameter the same as the
// rest.
query = "&" + query;
// Parameter prefix.
String prefix = "&" + encodedKey + "=";
ArrayList<String> values = new ArrayList<String>();
int start = 0;
int length = query.length();
while (start < length) {
start = query.indexOf(prefix, start);
do {
int nextAmpersand = query.indexOf('&', start);
int end = nextAmpersand != -1 ? nextAmpersand : query.length();
if (start == -1) {
// No more values.
int separator = query.indexOf('=', start);
if (separator > end || separator == -1) {
separator = end;
}
if (separator - start == encodedKey.length()
&& query.regionMatches(start, encodedKey, 0, encodedKey.length())) {
if (separator == end) {
values.add("");
} else {
values.add(decode(query.substring(separator + 1, end)));
}
}
// Move start to end of name.
if (nextAmpersand != -1) {
start = nextAmpersand + 1;
} else {
break;
}
// Move start to start of value.
start += prefix.length();
// Find end of value.
int end = query.indexOf('&', start);
if (end == -1) {
end = query.length();
}
String value = query.substring(start, end);
values.add(decode(value));
start = end;
}
} while (true);
return Collections.unmodifiableList(values);
}
@@ -1560,7 +1607,6 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
* @param key which will be encoded
* @throws UnsupportedOperationException if this isn't a hierarchical URI
* @throws NullPointerException if key is null
*
* @return the decoded value or null if no parameter is found
*/
public String getQueryParameter(String key) {
@@ -1577,34 +1623,33 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
final String encodedKey = encode(key, null);
final int encodedKeyLength = encodedKey.length();
final int length = query.length();
int start = 0;
do {
int nextAmpersand = query.indexOf('&', start);
int end = nextAmpersand != -1 ? nextAmpersand : length;
int encodedKeySearchIndex = 0;
final int encodedKeySearchEnd = query.length() - (encodedKeyLength + 1);
int separator = query.indexOf('=', start);
if (separator > end || separator == -1) {
separator = end;
}
while (encodedKeySearchIndex <= encodedKeySearchEnd) {
int keyIndex = query.indexOf(encodedKey, encodedKeySearchIndex);
if (keyIndex == -1) {
break;
}
final int equalsIndex = keyIndex + encodedKeyLength;
if (equalsIndex >= query.length()) {
break;
}
if (query.charAt(equalsIndex) != '=') {
encodedKeySearchIndex = equalsIndex + 1;
continue;
}
if (keyIndex == 0 || query.charAt(keyIndex - 1) == '&') {
int end = query.indexOf('&', equalsIndex);
if (end == -1) {
end = query.length();
if (separator - start == encodedKey.length()
&& query.regionMatches(start, encodedKey, 0, encodedKey.length())) {
if (separator == end) {
return "";
} else {
return decode(query.substring(separator + 1, end));
}
return decode(query.substring(equalsIndex + 1, end));
} else {
encodedKeySearchIndex = equalsIndex + 1;
}
}
// Move start to end of name.
if (nextAmpersand != -1) {
start = nextAmpersand + 1;
} else {
break;
}
} while (true);
return null;
}

View File

@@ -24,6 +24,9 @@ import junit.framework.TestCase;
import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class UriTest extends TestCase {
@@ -52,20 +55,20 @@ public class UriTest extends TestCase {
private void parcelAndUnparcel(Uri u) {
Parcel p = Parcel.obtain();
try {
Uri.writeToParcel(p, u);
p.setDataPosition(0);
assertEquals(u, Uri.CREATOR.createFromParcel(p));
try {
Uri.writeToParcel(p, u);
p.setDataPosition(0);
assertEquals(u, Uri.CREATOR.createFromParcel(p));
p.setDataPosition(0);
u = u.buildUpon().build();
Uri.writeToParcel(p, u);
p.setDataPosition(0);
assertEquals(u, Uri.CREATOR.createFromParcel(p));
}
finally {
p.recycle();
}
p.setDataPosition(0);
u = u.buildUpon().build();
Uri.writeToParcel(p, u);
p.setDataPosition(0);
assertEquals(u, Uri.CREATOR.createFromParcel(p));
}
finally {
p.recycle();
}
}
@SmallTest
@@ -603,4 +606,122 @@ public class UriTest extends TestCase {
assertEquals("", uri.getQueryParameter("b"));
assertEquals("", uri.getQueryParameter("c"));
}
public void testGetQueryParameterEmptyKey() {
Uri uri = Uri.parse("http://www.google.com/?=b");
assertEquals("b", uri.getQueryParameter(""));
}
public void testGetQueryParameterEmptyKey2() {
Uri uri = Uri.parse("http://www.google.com/?a=b&&c=d");
assertEquals("", uri.getQueryParameter(""));
}
public void testGetQueryParameterEmptyKey3() {
Uri uri = Uri.parse("http://www.google.com?");
assertEquals("", uri.getQueryParameter(""));
}
public void testGetQueryParameterEmptyKey4() {
Uri uri = Uri.parse("http://www.google.com?a=b&");
assertEquals("", uri.getQueryParameter(""));
}
public void testGetQueryParametersEmptyKey() {
Uri uri = Uri.parse("http://www.google.com/?=b&");
List<String> values = uri.getQueryParameters("");
assertEquals(2, values.size());
assertEquals("b", values.get(0));
assertEquals("", values.get(1));
}
public void testGetQueryParametersEmptyKey2() {
Uri uri = Uri.parse("http://www.google.com?");
List<String> values = uri.getQueryParameters("");
assertEquals(1, values.size());
assertEquals("", values.get(0));
}
public void testGetQueryParametersEmptyKey3() {
Uri uri = Uri.parse("http://www.google.com/?a=b&&c=d");
List<String> values = uri.getQueryParameters("");
assertEquals(1, values.size());
assertEquals("", values.get(0));
}
public void testGetQueryParameterNames() {
Uri uri = Uri.parse("http://test?a=1");
Set<String> names = uri.getQueryParameterNames();
assertEquals(1, names.size());
assertEquals("a", names.iterator().next());
}
public void testGetQueryParameterNamesEmptyKey() {
Uri uri = Uri.parse("http://www.google.com/?a=x&&c=z");
Set<String> names = uri.getQueryParameterNames();
Iterator<String> iter = names.iterator();
assertEquals(3, names.size());
assertEquals("a", iter.next());
assertEquals("", iter.next());
assertEquals("c", iter.next());
}
public void testGetQueryParameterNamesEmptyKey2() {
Uri uri = Uri.parse("http://www.google.com/?a=x&=d&c=z");
Set<String> names = uri.getQueryParameterNames();
Iterator<String> iter = names.iterator();
assertEquals(3, names.size());
assertEquals("a", iter.next());
assertEquals("", iter.next());
assertEquals("c", iter.next());
}
public void testGetQueryParameterNamesEmptyValues() {
Uri uri = Uri.parse("http://www.google.com/?a=foo&b=&c=");
Set<String> names = uri.getQueryParameterNames();
Iterator<String> iter = names.iterator();
assertEquals(3, names.size());
assertEquals("a", iter.next());
assertEquals("b", iter.next());
assertEquals("c", iter.next());
}
public void testGetQueryParameterNamesEdgeCases() {
Uri uri = Uri.parse("http://foo?a=bar&b=bar&c=&&d=baz&e&f&g=buzz&&&a&b=bar&h");
Set<String> names = uri.getQueryParameterNames();
Iterator<String> iter = names.iterator();
assertEquals(9, names.size());
assertEquals("a", iter.next());
assertEquals("b", iter.next());
assertEquals("c", iter.next());
assertEquals("", iter.next());
assertEquals("d", iter.next());
assertEquals("e", iter.next());
assertEquals("f", iter.next());
assertEquals("g", iter.next());
assertEquals("h", iter.next());
}
public void testGetQueryParameterNamesEscapedKeys() {
Uri uri = Uri.parse("http://www.google.com/?a%20b=foo&c%20d=");
Set<String> names = uri.getQueryParameterNames();
assertEquals(2, names.size());
Iterator<String> iter = names.iterator();
assertEquals("a b", iter.next());
assertEquals("c d", iter.next());
}
public void testGetQueryParameterEscapedKeys() {
Uri uri = Uri.parse("http://www.google.com/?a%20b=foo&c%20d=");
String value = uri.getQueryParameter("a b");
assertEquals("foo", value);
}
public void testClearQueryParameters() {
Uri uri = Uri.parse("http://www.google.com/?a=x&b=y&c=z").buildUpon()
.clearQuery().appendQueryParameter("foo", "bar").build();
Set<String> names = uri.getQueryParameterNames();
assertEquals(1, names.size());
assertEquals("foo", names.iterator().next());
}
}