SPR-5973: UriComponents now encapsulates a PathCompont, switching between string paths and path segment lists automatically.

This commit is contained in:
Arjen Poutsma 2011-09-14 14:09:57 +00:00
parent 782c2a4657
commit 3f2ea7f50e
6 changed files with 340 additions and 101 deletions

View File

@ -16,19 +16,20 @@
package org.springframework.web.servlet.support;
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import static org.junit.Assert.*;
/**
* @author Dave Syer
*
@ -56,7 +57,6 @@ public class RequestContextTests {
assertEquals("foo/bar", context.getContextUrl("bar"));
}
@org.junit.Ignore // TODO: Arjen to address in SPR-5973
@Test
public void testGetContextUrlStringMap() throws Exception {
request.setContextPath("foo/");

View File

@ -65,7 +65,7 @@ public final class UriComponents {
private final int port;
private final List<String> pathSegments;
private final PathComponent path;
private final MultiValueMap<String, String> queryParams;
@ -73,11 +73,11 @@ public final class UriComponents {
private final boolean encoded;
public UriComponents(String scheme,
UriComponents(String scheme,
String userInfo,
String host,
int port,
List<String> pathSegments,
PathComponent path,
MultiValueMap<String, String> queryParams,
String fragment,
boolean encoded) {
@ -85,10 +85,7 @@ public final class UriComponents {
this.userInfo = userInfo;
this.host = host;
this.port = port;
if (pathSegments == null) {
pathSegments = Collections.emptyList();
}
this.pathSegments = Collections.unmodifiableList(pathSegments);
this.path = path != null ? path : NULL_PATH_COMPONENT;
if (queryParams == null) {
queryParams = new LinkedMultiValueMap<String, String>(0);
}
@ -141,28 +138,7 @@ public final class UriComponents {
* @return the path. Can be {@code null}.
*/
public String getPath() {
if (!pathSegments.isEmpty()) {
StringBuilder pathBuilder = new StringBuilder();
for (String pathSegment : pathSegments) {
if (StringUtils.hasLength(pathSegment)) {
boolean startsWithSlash = pathSegment.charAt(0) == PATH_DELIMITER;
boolean endsWithSlash =
pathBuilder.length() > 0 && pathBuilder.charAt(pathBuilder.length() - 1) == PATH_DELIMITER;
if (!endsWithSlash && !startsWithSlash) {
pathBuilder.append('/');
}
else if (endsWithSlash && startsWithSlash) {
pathSegment = pathSegment.substring(1);
}
pathBuilder.append(pathSegment);
}
}
return pathBuilder.toString();
}
else {
return null;
}
return path.getPath();
}
/**
@ -170,9 +146,9 @@ public final class UriComponents {
*
* @return the path segments. Empty if no path has been set.
*/
public List<String> getPathSegments() {
return pathSegments;
}
public List<String> getPathSegments() {
return path.getPathSegments();
}
/**
* Returns the query.
@ -265,11 +241,7 @@ public final class UriComponents {
String encodedScheme = encodeUriComponent(this.scheme, encoding, Type.SCHEME);
String encodedUserInfo = encodeUriComponent(this.userInfo, encoding, Type.USER_INFO);
String encodedHost = encodeUriComponent(this.host, encoding, Type.HOST);
List<String> encodedPathSegments = new ArrayList<String>(this.pathSegments.size());
for (String pathSegment : this.pathSegments) {
String encodedPathSegment = encodeUriComponent(pathSegment, encoding, Type.PATH_SEGMENT);
encodedPathSegments.add(encodedPathSegment);
}
PathComponent encodedPath = path.encode(encoding);
MultiValueMap<String, String> encodedQueryParams =
new LinkedMultiValueMap<String, String>(this.queryParams.size());
for (Map.Entry<String, List<String>> entry : this.queryParams.entrySet()) {
@ -283,7 +255,7 @@ public final class UriComponents {
}
String encodedFragment = encodeUriComponent(this.fragment, encoding, Type.FRAGMENT);
return new UriComponents(encodedScheme, encodedUserInfo, encodedHost, this.port, encodedPathSegments,
return new UriComponents(encodedScheme, encodedUserInfo, encodedHost, this.port, encodedPath,
encodedQueryParams, encodedFragment, true);
}
@ -350,11 +322,7 @@ public final class UriComponents {
String expandedScheme = expandUriComponent(this.scheme, uriVariables);
String expandedUserInfo = expandUriComponent(this.userInfo, uriVariables);
String expandedHost = expandUriComponent(this.host, uriVariables);
List<String> expandedPathSegments = new ArrayList<String>(this.pathSegments.size());
for (String pathSegment : this.pathSegments) {
String expandedPathSegment = expandUriComponent(pathSegment, uriVariables);
expandedPathSegments.add(expandedPathSegment);
}
PathComponent expandedPath = path.expand(uriVariables);
MultiValueMap<String, String> expandedQueryParams =
new LinkedMultiValueMap<String, String>(this.queryParams.size());
for (Map.Entry<String, List<String>> entry : this.queryParams.entrySet()) {
@ -368,11 +336,11 @@ public final class UriComponents {
}
String expandedFragment = expandUriComponent(this.fragment, uriVariables);
return new UriComponents(expandedScheme, expandedUserInfo, expandedHost, this.port, expandedPathSegments,
return new UriComponents(expandedScheme, expandedUserInfo, expandedHost, this.port, expandedPath,
expandedQueryParams, expandedFragment, false);
}
private String expandUriComponent(String source, Map<String, ?> uriVariables) {
private static String expandUriComponent(String source, Map<String, ?> uriVariables) {
if (source == null) {
return null;
}
@ -408,11 +376,7 @@ public final class UriComponents {
String expandedScheme = expandUriComponent(this.scheme, valueIterator);
String expandedUserInfo = expandUriComponent(this.userInfo, valueIterator);
String expandedHost = expandUriComponent(this.host, valueIterator);
List<String> expandedPathSegments = new ArrayList<String>(this.pathSegments.size());
for (String pathSegment : this.pathSegments) {
String expandedPathSegment = expandUriComponent(pathSegment, valueIterator);
expandedPathSegments.add(expandedPathSegment);
}
PathComponent expandedPath = path.expand(valueIterator);
MultiValueMap<String, String> expandedQueryParams =
new LinkedMultiValueMap<String, String>(this.queryParams.size());
for (Map.Entry<String, List<String>> entry : this.queryParams.entrySet()) {
@ -426,11 +390,11 @@ public final class UriComponents {
}
String expandedFragment = expandUriComponent(this.fragment, valueIterator);
return new UriComponents(expandedScheme, expandedUserInfo, expandedHost, this.port, expandedPathSegments,
return new UriComponents(expandedScheme, expandedUserInfo, expandedHost, this.port, expandedPath,
expandedQueryParams, expandedFragment, false);
}
private String expandUriComponent(String source, Iterator<Object> valueIterator) {
private static String expandUriComponent(String source, Iterator<Object> valueIterator) {
if (source == null) {
return null;
}
@ -453,12 +417,12 @@ public final class UriComponents {
}
private String getVariableName(String match) {
private static String getVariableName(String match) {
int colonIdx = match.indexOf(':');
return colonIdx == -1 ? match : match.substring(0, colonIdx);
}
protected String getVariableValueAsString(Object variableValue) {
private static String getVariableValueAsString(Object variableValue) {
return variableValue != null ? variableValue.toString() : "";
}
@ -497,9 +461,12 @@ public final class UriComponents {
}
String path = getPath();
if (path != null) {
uriBuilder.append(path);
}
if (StringUtils.hasLength(path)) {
if (uriBuilder.length() != 0 && path.charAt(0) != PATH_DELIMITER) {
uriBuilder.append(PATH_DELIMITER);
}
uriBuilder.append(path);
}
String query = getQuery();
if (query != null) {
@ -526,7 +493,11 @@ public final class UriComponents {
return new URI(toUriString());
}
else {
return new URI(getScheme(), getUserInfo(), getHost(), getPort(), getPath(), getQuery(),
String path = getPath();
if (StringUtils.hasLength(path) && path.charAt(0) != PATH_DELIMITER) {
path = PATH_DELIMITER + path;
}
return new URI(getScheme(), getUserInfo(), getHost(), getPort(), path, getQuery(),
getFragment());
}
}
@ -555,7 +526,7 @@ public final class UriComponents {
if (port != other.port) {
return false;
}
if (!pathSegments.equals(other.pathSegments)) {
if (!path.equals(other.path)) {
return false;
}
if (!queryParams.equals(other.queryParams)) {
@ -577,7 +548,7 @@ public final class UriComponents {
result = 31 * result + (userInfo != null ? userInfo.hashCode() : 0);
result = 31 * result + (host != null ? host.hashCode() : 0);
result = 31 * result + port;
result = 31 * result + pathSegments.hashCode();
result = 31 * result + path.hashCode();
result = 31 * result + queryParams.hashCode();
result = 31 * result + (fragment != null ? fragment.hashCode() : 0);
return result;
@ -740,4 +711,186 @@ public final class UriComponents {
}
/**
* Defines the contract for path (segments).
*/
interface PathComponent {
String getPath();
List<String> getPathSegments();
PathComponent encode(String encoding) throws UnsupportedEncodingException;
PathComponent expand(Map<String, ?> uriVariables);
PathComponent expand(Iterator<Object> valueIterator);
}
/**
* Represents a path backed by a string.
*/
final static class FullPathComponent implements PathComponent {
private final String path;
FullPathComponent(String path) {
this.path = path;
}
public String getPath() {
return path;
}
public List<String> getPathSegments() {
String delimiter = new String(new char[]{PATH_DELIMITER});
String[] pathSegments = StringUtils.tokenizeToStringArray(path, delimiter);
return Collections.unmodifiableList(Arrays.asList(pathSegments));
}
public PathComponent encode(String encoding) throws UnsupportedEncodingException {
String encodedPath = encodeUriComponent(getPath(),encoding, Type.PATH);
return new FullPathComponent(encodedPath);
}
public PathComponent expand(Map<String, ?> uriVariables) {
String expandedPath = expandUriComponent(getPath(), uriVariables);
return new FullPathComponent(expandedPath);
}
public PathComponent expand(Iterator<Object> valueIterator) {
String expandedPath = expandUriComponent(getPath(), valueIterator);
return new FullPathComponent(expandedPath);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o instanceof FullPathComponent) {
FullPathComponent other = (FullPathComponent) o;
return this.getPath().equals(other.getPath());
}
return false;
}
@Override
public int hashCode() {
return getPath().hashCode();
}
}
/**
* Represents a path backed by a string list (i.e. path segments).
*/
final static class PathSegmentComponent implements PathComponent {
private final List<String> pathSegments;
PathSegmentComponent(List<String> pathSegments) {
this.pathSegments = Collections.unmodifiableList(pathSegments);
}
public String getPath() {
StringBuilder pathBuilder = new StringBuilder();
pathBuilder.append(PATH_DELIMITER);
for (Iterator<String> iterator = pathSegments.iterator(); iterator.hasNext(); ) {
String pathSegment = iterator.next();
pathBuilder.append(pathSegment);
if (iterator.hasNext()) {
pathBuilder.append(PATH_DELIMITER);
}
}
return pathBuilder.toString();
}
public List<String> getPathSegments() {
return pathSegments;
}
public PathComponent encode(String encoding) throws UnsupportedEncodingException {
List<String> pathSegments = getPathSegments();
List<String> encodedPathSegments = new ArrayList<String>(pathSegments.size());
for (String pathSegment : pathSegments) {
String encodedPathSegment = encodeUriComponent(pathSegment, encoding, Type.PATH_SEGMENT);
encodedPathSegments.add(encodedPathSegment);
}
return new PathSegmentComponent(encodedPathSegments);
}
public PathComponent expand(Map<String, ?> uriVariables) {
List<String> pathSegments = getPathSegments();
List<String> expandedPathSegments = new ArrayList<String>(pathSegments.size());
for (String pathSegment : pathSegments) {
String expandedPathSegment = expandUriComponent(pathSegment, uriVariables);
expandedPathSegments.add(expandedPathSegment);
}
return new PathSegmentComponent(expandedPathSegments);
}
public PathComponent expand(Iterator<Object> valueIterator) {
List<String> pathSegments = getPathSegments();
List<String> expandedPathSegments = new ArrayList<String>(pathSegments.size());
for (String pathSegment : pathSegments) {
String expandedPathSegment = expandUriComponent(pathSegment, valueIterator);
expandedPathSegments.add(expandedPathSegment);
}
return new PathSegmentComponent(expandedPathSegments);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o instanceof PathSegmentComponent) {
PathSegmentComponent other = (PathSegmentComponent) o;
return this.getPathSegments().equals(other.getPathSegments());
}
return false;
}
@Override
public int hashCode() {
return getPathSegments().hashCode();
}
}
/**
* Represents an empty path.
*/
final static PathComponent NULL_PATH_COMPONENT = new PathComponent() {
public String getPath() {
return null;
}
public List<String> getPathSegments() {
return Collections.emptyList();
}
public PathComponent encode(String encoding) throws UnsupportedEncodingException {
return this;
}
public PathComponent expand(Map<String, ?> uriVariables) {
return this;
}
public PathComponent expand(Iterator<Object> valueIterator) {
return this;
}
@Override
public boolean equals(Object o) {
return this == o;
}
@Override
public int hashCode() {
return 42;
}
};
}

View File

@ -51,8 +51,6 @@ import org.springframework.util.StringUtils;
*/
public class UriComponentsBuilder {
private static final char PATH_DELIMITER = '/';
private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("([^&=]+)=?([^&=]+)?");
private static final String SCHEME_PATTERN = "([^:/?#]+):";
@ -89,7 +87,7 @@ public class UriComponentsBuilder {
private int port = -1;
private final List<String> pathSegments = new ArrayList<String>();
private PathComponentBuilder pathBuilder = NULL_PATH_COMPONENT_BUILDER;
private final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
@ -219,7 +217,7 @@ public class UriComponentsBuilder {
* @return the URI components
*/
public UriComponents build(boolean encoded) {
return new UriComponents(scheme, userInfo, host, port, pathSegments, queryParams, fragment, encoded);
return new UriComponents(scheme, userInfo, host, port, pathBuilder.build(), queryParams, fragment, encoded);
}
// URI components methods
@ -246,8 +244,7 @@ public class UriComponentsBuilder {
this.port = uri.getPort();
}
if (StringUtils.hasLength(uri.getPath())) {
this.pathSegments.clear();
path(uri.getPath());
this.pathBuilder = new FullPathComponentBuilder(uri.getPath());
}
if (StringUtils.hasLength(uri.getQuery())) {
this.queryParams.clear();
@ -307,11 +304,7 @@ public class UriComponentsBuilder {
return this;
}
private String portAsString() {
return this.port != -1 ? Integer.toString(this.port) : null;
}
/**
/**
* Appends the given path to the existing path of this builder. The given path may contain URI template variables.
*
* @param path the URI path
@ -319,10 +312,9 @@ public class UriComponentsBuilder {
*/
public UriComponentsBuilder path(String path) {
if (path != null) {
String[] pathSegments = StringUtils.tokenizeToStringArray(path, "/");
pathSegment(pathSegments);
this.pathBuilder = this.pathBuilder.appendPath(path);
} else {
pathSegments.clear();
this.pathBuilder = NULL_PATH_COMPONENT_BUILDER;
}
return this;
}
@ -331,15 +323,14 @@ public class UriComponentsBuilder {
* Appends the given path segments to the existing path of this builder. Each given path segments may contain URI
* template variables.
*
* @param segments the URI path segments
* @param pathSegments the URI path segments
* @return this UriComponentsBuilder
*/
public UriComponentsBuilder pathSegment(String... segments) throws IllegalArgumentException {
Assert.notNull(segments, "'segments' must not be null");
Collections.addAll(this.pathSegments, segments);
return this;
}
public UriComponentsBuilder pathSegment(String... pathSegments) throws IllegalArgumentException {
Assert.notNull(pathSegments, "'segments' must not be null");
this.pathBuilder = this.pathBuilder.appendPathSegments(pathSegments);
return this;
}
/**
* Appends the given query to the existing query of this builder. The given query may contain URI template variables.
@ -404,4 +395,100 @@ public class UriComponentsBuilder {
return this;
}
/**
* Represents a builder for {@link org.springframework.web.util.UriComponents.PathComponent}
*/
private interface PathComponentBuilder {
UriComponents.PathComponent build();
PathComponentBuilder appendPath(String path);
PathComponentBuilder appendPathSegments(String... pathSegments);
}
/**
* Represents a builder for full string paths.
*/
private static class FullPathComponentBuilder implements PathComponentBuilder {
private final StringBuilder path;
private FullPathComponentBuilder(String path) {
this.path = new StringBuilder(path);
}
public UriComponents.PathComponent build() {
return new UriComponents.FullPathComponent(path.toString());
}
public PathComponentBuilder appendPath(String path) {
this.path.append(path);
return this;
}
public PathComponentBuilder appendPathSegments(String... pathSegments) {
for (String pathSegment : pathSegments) {
final boolean pathEndsInSlash = path.length() > 0 && path.charAt(path.length() - 1) == '/';
final boolean segmentStartsWithSlash = pathSegment.charAt(0) == '/';
if (path.length() > 0 && !pathEndsInSlash && !segmentStartsWithSlash) {
path.append('/');
} else if (pathEndsInSlash && segmentStartsWithSlash) {
pathSegment = pathSegment.substring(1);
if (pathSegment.length() == 0)
continue;
}
path.append(pathSegment);
}
return this;
}
}
/**
* Represents a builder for paths segment paths.
*/
private static class PathSegmentComponentBuilder implements PathComponentBuilder {
private final List<String> pathSegments = new ArrayList<String>();
private PathSegmentComponentBuilder(String... pathSegments) {
Collections.addAll(this.pathSegments, pathSegments);
}
public UriComponents.PathComponent build() {
return new UriComponents.PathSegmentComponent(pathSegments);
}
public PathComponentBuilder appendPath(String path) {
String[] pathSegments = StringUtils.tokenizeToStringArray(path, "/");
Collections.addAll(this.pathSegments, pathSegments);
return this;
}
public PathComponentBuilder appendPathSegments(String... pathSegments) {
Collections.addAll(this.pathSegments, pathSegments);
return this;
}
}
/**
* Represents a builder for an empty path.
*/
private static PathComponentBuilder NULL_PATH_COMPONENT_BUILDER = new PathComponentBuilder() {
public UriComponents.PathComponent build() {
return UriComponents.NULL_PATH_COMPONENT;
}
public PathComponentBuilder appendPath(String path) {
return new FullPathComponentBuilder(path);
}
public PathComponentBuilder appendPathSegments(String... pathSegments) {
return new PathSegmentComponentBuilder(pathSegments);
}
};
}

View File

@ -36,7 +36,7 @@ public class UriComponentsBuilderTests {
UriComponents result = builder.scheme("http").host("example.com").path("foo").queryParam("bar").fragment("baz").build();
assertEquals("http", result.getScheme());
assertEquals("example.com", result.getHost());
assertEquals("/foo", result.getPath());
assertEquals("foo", result.getPath());
assertEquals("bar", result.getQuery());
assertEquals("baz", result.getFragment());
@ -47,7 +47,7 @@ public class UriComponentsBuilderTests {
@Test
public void fromPath() throws URISyntaxException {
UriComponents result = UriComponentsBuilder.fromPath("foo").queryParam("bar").fragment("baz").build();
assertEquals("/foo", result.getPath());
assertEquals("foo", result.getPath());
assertEquals("bar", result.getQuery());
assertEquals("baz", result.getFragment());
@ -114,7 +114,7 @@ public class UriComponentsBuilderTests {
assertNull(result.getUserInfo());
assertNull(result.getHost());
assertEquals(-1, result.getPort());
assertEquals("/docs/guide/collections/designfaq.html", result.getPath());
assertEquals("docs/guide/collections/designfaq.html", result.getPath());
assertNull(result.getQuery());
assertEquals("28", result.getFragment());
}

View File

@ -26,7 +26,6 @@ import static org.junit.Assert.*;
/** @author Arjen Poutsma */
public class UriComponentsTests {
@Test
public void encode() {
UriComponents uriComponents = UriComponentsBuilder.fromPath("/hotel list").build();

View File

@ -111,19 +111,19 @@ public class UriUtilsTests {
UriUtils.encodeUri("http://www.ietf.org/rfc/rfc3986.txt", ENC));
assertEquals("Invalid encoded URI", "https://www.ietf.org/rfc/rfc3986.txt",
UriUtils.encodeUri("https://www.ietf.org/rfc/rfc3986.txt", ENC));
assertEquals("Invalid encoded URI", "http://www.google.com?q=Z%C3%BCrich",
UriUtils.encodeUri("http://www.google.com?q=Z\u00fcrich", ENC));
assertEquals("Invalid encoded URI", "http://www.google.com/?q=Z%C3%BCrich",
UriUtils.encodeUri("http://www.google.com/?q=Z\u00fcrich", ENC));
assertEquals("Invalid encoded URI",
"http://arjen:foobar@java.sun.com:80/javase/6/docs/api/java/util/BitSet.html?foo=bar#and(java.util.BitSet)",
UriUtils.encodeUri(
"http://arjen:foobar@java.sun.com:80/javase/6/docs/api/java/util/BitSet.html?foo=bar#and(java.util.BitSet)",
ENC));
assertEquals("Invalid encoded URI", "http://java.sun.com/j2se/1.3",
UriUtils.encodeUri("http://java.sun.com/j2se/1.3", ENC));
assertEquals("Invalid encoded URI", "/docs/guide/collections/designfaq.html#28",
UriUtils.encodeUri("/docs/guide/collections/designfaq.html#28", ENC));
assertEquals("Invalid encoded URI", "/../../../demo/jfc/SwingSet2/src/SwingSet2.java",
UriUtils.encodeUri("/../../../demo/jfc/SwingSet2/src/SwingSet2.java", ENC));
assertEquals("Invalid encoded URI", "http://java.sun.com/j2se/1.3/",
UriUtils.encodeUri("http://java.sun.com/j2se/1.3/", ENC));
assertEquals("Invalid encoded URI", "docs/guide/collections/designfaq.html#28",
UriUtils.encodeUri("docs/guide/collections/designfaq.html#28", ENC));
assertEquals("Invalid encoded URI", "../../../demo/jfc/SwingSet2/src/SwingSet2.java",
UriUtils.encodeUri("../../../demo/jfc/SwingSet2/src/SwingSet2.java", ENC));
assertEquals("Invalid encoded URI", "file:///~/calendar", UriUtils.encodeUri("file:///~/calendar", ENC));
assertEquals("Invalid encoded URI", "http://example.com/query=foo@bar",
UriUtils.encodeUri("http://example.com/query=foo@bar", ENC));
@ -136,8 +136,8 @@ public class UriUtilsTests {
UriUtils.encodeHttpUrl("http://www.ietf.org/rfc/rfc3986.txt", ENC));
assertEquals("Invalid encoded URI", "https://www.ietf.org/rfc/rfc3986.txt",
UriUtils.encodeHttpUrl("https://www.ietf.org/rfc/rfc3986.txt", ENC));
assertEquals("Invalid encoded HTTP URL", "http://www.google.com?q=Z%C3%BCrich",
UriUtils.encodeHttpUrl("http://www.google.com?q=Z\u00fcrich", ENC));
assertEquals("Invalid encoded HTTP URL", "http://www.google.com/?q=Z%C3%BCrich",
UriUtils.encodeHttpUrl("http://www.google.com/?q=Z\u00fcrich", ENC));
assertEquals("Invalid encoded HTTP URL", "http://ws.geonames.org/searchJSON?q=T%C5%8Dky%C5%8D&style=FULL&maxRows=300",
UriUtils.encodeHttpUrl("http://ws.geonames.org/searchJSON?q=T\u014dky\u014d&style=FULL&maxRows=300", ENC));
assertEquals("Invalid encoded HTTP URL",
@ -146,8 +146,8 @@ public class UriUtilsTests {
"http://arjen:foobar@java.sun.com:80/javase/6/docs/api/java/util/BitSet.html?foo=bar", ENC));
assertEquals("Invalid encoded HTTP URL", "http://search.twitter.com/search.atom?q=%23avatar",
UriUtils.encodeHttpUrl("http://search.twitter.com/search.atom?q=#avatar", ENC));
assertEquals("Invalid encoded HTTP URL", "http://java.sun.com/j2se/1.3",
UriUtils.encodeHttpUrl("http://java.sun.com/j2se/1.3", ENC));
assertEquals("Invalid encoded HTTP URL", "http://java.sun.com/j2se/1.3/",
UriUtils.encodeHttpUrl("http://java.sun.com/j2se/1.3/", ENC));
assertEquals("Invalid encoded HTTP URL", "http://example.com/query=foo@bar",
UriUtils.encodeHttpUrl("http://example.com/query=foo@bar", ENC));
}