Browse Source

SPR-5973: Changed UriComponent from inner type to top-level enum

pull/7/head
Arjen Poutsma 13 years ago
parent
commit
1d75e1b250
  1. 42
      org.springframework.web/src/main/java/org/springframework/web/util/UriBuilder.java
  2. 168
      org.springframework.web/src/main/java/org/springframework/web/util/UriComponent.java
  3. 8
      org.springframework.web/src/main/java/org/springframework/web/util/UriTemplate.java
  4. 142
      org.springframework.web/src/main/java/org/springframework/web/util/UriUtils.java
  5. 8
      org.springframework.web/src/test/java/org/springframework/web/util/UriBuilderTests.java

42
org.springframework.web/src/main/java/org/springframework/web/util/UriBuilder.java

@ -52,6 +52,7 @@ import org.springframework.util.StringUtils; @@ -52,6 +52,7 @@ import org.springframework.util.StringUtils;
* values are encoded when a URI is built.
* Template parameter regular expressions are ignored when building a URI, i.e.
* no validation is performed.
*
* <p>Inspired by {@link javax.ws.rs.core.UriBuilder}.
*
* @author Arjen Poutsma
@ -132,7 +133,8 @@ public class UriBuilder { @@ -132,7 +133,8 @@ public class UriBuilder {
StringBuilder uriBuilder = new StringBuilder();
if (scheme != null) {
uriBuilder.append(scheme).append(':');
uriBuilder.append(scheme);
uriBuilder.append(':');
}
if (userInfo != null || host != null || port != -1) {
@ -218,7 +220,7 @@ public class UriBuilder { @@ -218,7 +220,7 @@ public class UriBuilder {
UriTemplate template;
if (scheme != null) {
template = new UriTemplate(scheme, UriUtils.SCHEME_COMPONENT);
template = new UriTemplate(scheme, UriComponent.SCHEME);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariables));
uriBuilder.append(':');
}
@ -227,13 +229,13 @@ public class UriBuilder { @@ -227,13 +229,13 @@ public class UriBuilder {
uriBuilder.append("//");
if (StringUtils.hasLength(userInfo)) {
template = new UriTemplate(userInfo, UriUtils.USER_INFO_COMPONENT);
template = new UriTemplate(userInfo, UriComponent.USER_INFO);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariables));
uriBuilder.append('@');
}
if (host != null) {
template = new UriTemplate(host, UriUtils.HOST_COMPONENT);
template = new UriTemplate(host, UriComponent.HOST);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariables));
}
@ -254,19 +256,19 @@ public class UriBuilder { @@ -254,19 +256,19 @@ public class UriBuilder {
else if (endsWithSlash && startsWithSlash) {
pathSegment = pathSegment.substring(1);
}
template = new UriTemplate(pathSegment, UriUtils.PATH_SEGMENT_COMPONENT);
template = new UriTemplate(pathSegment, UriComponent.PATH_SEGMENT);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariables));
}
}
if (queryBuilder.length() > 0) {
uriBuilder.append('?');
template = new UriTemplate(queryBuilder.toString(), UriUtils.QUERY_COMPONENT);
template = new UriTemplate(queryBuilder.toString(), UriComponent.QUERY);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariables));
}
if (StringUtils.hasLength(fragment)) {
uriBuilder.append('#');
template = new UriTemplate(fragment, UriUtils.FRAGMENT_COMPONENT);
template = new UriTemplate(fragment, UriComponent.FRAGMENT);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariables));
}
@ -306,7 +308,7 @@ public class UriBuilder { @@ -306,7 +308,7 @@ public class UriBuilder {
UriTemplate template;
if (scheme != null) {
template = new UriTemplate(scheme, UriUtils.SCHEME_COMPONENT);
template = new UriTemplate(scheme, UriComponent.SCHEME);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariableValues));
uriBuilder.append(':');
}
@ -315,13 +317,13 @@ public class UriBuilder { @@ -315,13 +317,13 @@ public class UriBuilder {
uriBuilder.append("//");
if (StringUtils.hasLength(userInfo)) {
template = new UriTemplate(userInfo, UriUtils.USER_INFO_COMPONENT);
template = new UriTemplate(userInfo, UriComponent.USER_INFO);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariableValues));
uriBuilder.append('@');
}
if (host != null) {
template = new UriTemplate(host, UriUtils.HOST_COMPONENT);
template = new UriTemplate(host, UriComponent.HOST);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariableValues));
}
@ -342,20 +344,20 @@ public class UriBuilder { @@ -342,20 +344,20 @@ public class UriBuilder {
else if (endsWithSlash && startsWithSlash) {
pathSegment = pathSegment.substring(1);
}
template = new UriTemplate(pathSegment, UriUtils.PATH_SEGMENT_COMPONENT);
template = new UriTemplate(pathSegment, UriComponent.PATH_SEGMENT);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariableValues));
}
}
if (queryBuilder.length() > 0) {
uriBuilder.append('?');
template = new UriTemplate(queryBuilder.toString(), UriUtils.QUERY_COMPONENT);
template = new UriTemplate(queryBuilder.toString(), UriComponent.QUERY);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariableValues));
}
if (StringUtils.hasLength(fragment)) {
uriBuilder.append('#');
template = new UriTemplate(fragment, UriUtils.FRAGMENT_COMPONENT);
template = new UriTemplate(fragment, UriComponent.FRAGMENT);
uriBuilder.append(template.expandAsString(encodeUriVariableValues, uriVariableValues));
}
@ -411,7 +413,7 @@ public class UriBuilder { @@ -411,7 +413,7 @@ public class UriBuilder {
public UriBuilder scheme(String scheme) {
if (scheme != null) {
Assert.hasLength(scheme, "'scheme' must not be empty");
this.scheme = UriUtils.encode(scheme, UriUtils.SCHEME_COMPONENT, true);
this.scheme = UriUtils.encode(scheme, UriComponent.SCHEME, true);
}
else {
this.scheme = null;
@ -429,7 +431,7 @@ public class UriBuilder { @@ -429,7 +431,7 @@ public class UriBuilder {
public UriBuilder userInfo(String userInfo) {
if (userInfo != null) {
Assert.hasLength(userInfo, "'userInfo' must not be empty");
this.userInfo = UriUtils.encode(userInfo, UriUtils.USER_INFO_COMPONENT, true);
this.userInfo = UriUtils.encode(userInfo, UriComponent.USER_INFO, true);
}
else {
this.userInfo = null;
@ -447,7 +449,7 @@ public class UriBuilder { @@ -447,7 +449,7 @@ public class UriBuilder {
public UriBuilder host(String host) {
if (host != null) {
Assert.hasLength(host, "'host' must not be empty");
this.host = UriUtils.encode(host, UriUtils.HOST_COMPONENT, true);
this.host = UriUtils.encode(host, UriComponent.HOST, true);
}
else {
this.host = null;
@ -490,7 +492,7 @@ public class UriBuilder { @@ -490,7 +492,7 @@ public class UriBuilder {
public UriBuilder pathSegment(String... segments) throws IllegalArgumentException {
Assert.notNull(segments, "'segments' must not be null");
for (String segment : segments) {
this.pathSegments.add(UriUtils.encode(segment, UriUtils.PATH_SEGMENT_COMPONENT, true));
this.pathSegments.add(UriUtils.encode(segment, UriComponent.PATH_SEGMENT, true));
}
return this;
@ -508,7 +510,7 @@ public class UriBuilder { @@ -508,7 +510,7 @@ public class UriBuilder {
public UriBuilder queryParam(String name, Object... values) {
Assert.notNull(name, "'name' must not be null");
String encodedName = UriUtils.encode(name, UriUtils.QUERY_PARAM_COMPONENT, true);
String encodedName = UriUtils.encode(name, UriComponent.QUERY_PARAM, true);
if (ObjectUtils.isEmpty(values)) {
if (queryBuilder.length() != 0) {
@ -526,7 +528,7 @@ public class UriBuilder { @@ -526,7 +528,7 @@ public class UriBuilder {
String valueAsString = value != null ? value.toString() : "";
if (valueAsString.length() != 0) {
queryBuilder.append('=');
queryBuilder.append(UriUtils.encode(valueAsString, UriUtils.QUERY_PARAM_COMPONENT, true));
queryBuilder.append(UriUtils.encode(valueAsString, UriComponent.QUERY_PARAM, true));
}
}
@ -544,7 +546,7 @@ public class UriBuilder { @@ -544,7 +546,7 @@ public class UriBuilder {
public UriBuilder fragment(String fragment) {
if (fragment != null) {
Assert.hasLength(fragment, "'fragment' must not be empty");
this.fragment = UriUtils.encode(fragment, UriUtils.FRAGMENT_COMPONENT, true);
this.fragment = UriUtils.encode(fragment, UriComponent.FRAGMENT, true);
}
else {
this.fragment = null;

168
org.springframework.web/src/main/java/org/springframework/web/util/UriComponent.java

@ -0,0 +1,168 @@ @@ -0,0 +1,168 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.util;
/**
* Enumeration used to identify the parts of a URI.
*
* <p>Contains methods to indicate whether a given character is valid in a specific URI component.
*
* @author Arjen Poutsma
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>
* @since 3.1
*/
public enum UriComponent {
SCHEME {
@Override
public boolean isAllowed(int c) {
return isAlpha(c) || isDigit(c) || '+' == c || '-' == c || '.' == c;
}
},
AUTHORITY {
@Override
public boolean isAllowed(int c) {
return isUnreserved(c) || isSubDelimiter(c) || ':' == c || '@' == c;
}
},
USER_INFO {
@Override
public boolean isAllowed(int c) {
return isUnreserved(c) || isSubDelimiter(c) || ':' == c;
}
},
HOST {
@Override
public boolean isAllowed(int c) {
return isUnreserved(c) || isSubDelimiter(c);
}
},
PORT {
@Override
public boolean isAllowed(int c) {
return isDigit(c);
}
},
PATH {
@Override
public boolean isAllowed(int c) {
return isPchar(c) || '/' == c;
}
},
PATH_SEGMENT {
@Override
public boolean isAllowed(int c) {
return isPchar(c);
}
},
QUERY {
@Override
public boolean isAllowed(int c) {
return isPchar(c) || '/' == c || '?' == c;
}
},
QUERY_PARAM {
@Override
public boolean isAllowed(int c) {
if ('=' == c || '+' == c || '&' == c) {
return false;
}
else {
return isPchar(c) || '/' == c || '?' == c;
}
}
},
FRAGMENT {
@Override
public boolean isAllowed(int c) {
return isPchar(c) || '/' == c || '?' == c;
}
};
/**
* Indicates whether the given character is allowed in this URI component.
*
* @param c the character
* @return {@code true} if the character is allowed; {@code false} otherwise
*/
public abstract boolean isAllowed(int c);
/**
* Indicates whether the given character is in the {@code ALPHA} set.
*
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
*/
protected boolean isAlpha(int c) {
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
/**
* Indicates whether the given character is in the {@code DIGIT} set.
*
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
*/
protected boolean isDigit(int c) {
return c >= '0' && c <= '9';
}
/**
* Indicates whether the given character is in the {@code gen-delims} set.
*
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
*/
protected boolean isGenericDelimiter(int c) {
return ':' == c || '/' == c || '?' == c || '#' == c || '[' == c || ']' == c || '@' == c;
}
/**
* Indicates whether the given character is in the {@code sub-delims} set.
*
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
*/
protected boolean isSubDelimiter(int c) {
return '!' == c || '$' == c || '&' == c || '\'' == c || '(' == c || ')' == c || '*' == c || '+' == c ||
',' == c || ';' == c || '=' == c;
}
/**
* Indicates whether the given character is in the {@code reserved} set.
*
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
*/
protected boolean isReserved(char c) {
return isGenericDelimiter(c) || isReserved(c);
}
/**
* Indicates whether the given character is in the {@code unreserved} set.
*
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
*/
protected boolean isUnreserved(int c) {
return isAlpha(c) || isDigit(c) || '-' == c || '.' == c || '_' == c || '~' == c;
}
/**
* Indicates whether the given character is in the {@code pchar} set.
*
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
*/
protected boolean isPchar(int c) {
return isUnreserved(c) || isSubDelimiter(c) || ':' == c || '@' == c;
}
}

8
org.springframework.web/src/main/java/org/springframework/web/util/UriTemplate.java

@ -56,7 +56,7 @@ public class UriTemplate implements Serializable { @@ -56,7 +56,7 @@ public class UriTemplate implements Serializable {
private final String uriTemplate;
private final UriUtils.UriComponent uriComponent;
private final UriComponent uriComponent;
/**
@ -75,7 +75,7 @@ public class UriTemplate implements Serializable { @@ -75,7 +75,7 @@ public class UriTemplate implements Serializable {
* Construct a new {@link UriTemplate} with the given URI String.
* @param uriTemplate the URI template string
*/
public UriTemplate(String uriTemplate, UriUtils.UriComponent uriComponent) {
public UriTemplate(String uriTemplate, UriComponent uriComponent) {
Parser parser = new Parser(uriTemplate);
this.uriTemplate = uriTemplate;
this.variableNames = parser.getVariableNames();
@ -110,7 +110,7 @@ public class UriTemplate implements Serializable { @@ -110,7 +110,7 @@ public class UriTemplate implements Serializable {
* or if it does not contain values for all the variable names
*/
public URI expand(Map<String, ?> uriVariables) {
return encodeUri(expandAsString(true, uriVariables));
return encodeUri(expandAsString(false, uriVariables));
}
/**
@ -159,7 +159,7 @@ public class UriTemplate implements Serializable { @@ -159,7 +159,7 @@ public class UriTemplate implements Serializable {
* or if it does not contain sufficient variables
*/
public URI expand(Object... uriVariableValues) {
return encodeUri(expandAsString(true, uriVariableValues));
return encodeUri(expandAsString(false, uriVariableValues));
}
/**

142
org.springframework.web/src/main/java/org/springframework/web/util/UriUtils.java

@ -239,7 +239,7 @@ public abstract class UriUtils { @@ -239,7 +239,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodeScheme(String scheme, String encoding) throws UnsupportedEncodingException {
return encode(scheme, encoding, SCHEME_COMPONENT, false);
return encode(scheme, encoding, UriComponent.SCHEME, false);
}
/**
@ -250,7 +250,7 @@ public abstract class UriUtils { @@ -250,7 +250,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodeAuthority(String authority, String encoding) throws UnsupportedEncodingException {
return encode(authority, encoding, AUTHORITY_COMPONENT, false);
return encode(authority, encoding, UriComponent.AUTHORITY, false);
}
/**
@ -261,7 +261,7 @@ public abstract class UriUtils { @@ -261,7 +261,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodeUserInfo(String userInfo, String encoding) throws UnsupportedEncodingException {
return encode(userInfo, encoding, USER_INFO_COMPONENT, false);
return encode(userInfo, encoding, UriComponent.USER_INFO, false);
}
/**
@ -272,7 +272,7 @@ public abstract class UriUtils { @@ -272,7 +272,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodeHost(String host, String encoding) throws UnsupportedEncodingException {
return encode(host, encoding, HOST_COMPONENT, false);
return encode(host, encoding, UriComponent.HOST, false);
}
/**
@ -283,7 +283,7 @@ public abstract class UriUtils { @@ -283,7 +283,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodePort(String port, String encoding) throws UnsupportedEncodingException {
return encode(port, encoding, PORT_COMPONENT, false);
return encode(port, encoding, UriComponent.PORT, false);
}
/**
@ -294,7 +294,7 @@ public abstract class UriUtils { @@ -294,7 +294,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodePath(String path, String encoding) throws UnsupportedEncodingException {
return encode(path, encoding, PATH_COMPONENT, false);
return encode(path, encoding, UriComponent.PATH, false);
}
/**
@ -305,7 +305,7 @@ public abstract class UriUtils { @@ -305,7 +305,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodePathSegment(String segment, String encoding) throws UnsupportedEncodingException {
return encode(segment, encoding, PATH_SEGMENT_COMPONENT, false);
return encode(segment, encoding, UriComponent.PATH_SEGMENT, false);
}
/**
@ -316,7 +316,7 @@ public abstract class UriUtils { @@ -316,7 +316,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodeQuery(String query, String encoding) throws UnsupportedEncodingException {
return encode(query, encoding, QUERY_COMPONENT, false);
return encode(query, encoding, UriComponent.QUERY, false);
}
/**
@ -327,7 +327,7 @@ public abstract class UriUtils { @@ -327,7 +327,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodeQueryParam(String queryParam, String encoding) throws UnsupportedEncodingException {
return encode(queryParam, encoding, QUERY_PARAM_COMPONENT, false);
return encode(queryParam, encoding, UriComponent.QUERY_PARAM, false);
}
/**
@ -338,7 +338,7 @@ public abstract class UriUtils { @@ -338,7 +338,7 @@ public abstract class UriUtils {
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
*/
public static String encodeFragment(String fragment, String encoding) throws UnsupportedEncodingException {
return encode(fragment, encoding, FRAGMENT_COMPONENT, false);
return encode(fragment, encoding, UriComponent.FRAGMENT, false);
}
/**
@ -478,126 +478,4 @@ public abstract class UriUtils { @@ -478,126 +478,4 @@ public abstract class UriUtils {
return changed ? new String(bos.toByteArray(), encoding) : source;
}
/**
* Defines the contract for an URI component, i.e. scheme, host, path, etc.
*/
public interface UriComponent {
/**
* Specifies whether the given character is allowed in this URI component.
* @param c the character
* @return {@code true} if the character is allowed; {@code false} otherwise
*/
boolean isAllowed(int c);
}
private static abstract class AbstractUriComponent implements UriComponent {
protected boolean isAlpha(int c) {
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
protected boolean isDigit(int c) {
return c >= '0' && c <= '9';
}
protected boolean isGenericDelimiter(int c) {
return ':' == c || '/' == c || '?' == c || '#' == c || '[' == c || ']' == c || '@' == c;
}
protected boolean isSubDelimiter(int c) {
return '!' == c || '$' == c || '&' == c || '\'' == c || '(' == c || ')' == c || '*' == c || '+' == c ||
',' == c || ';' == c || '=' == c;
}
protected boolean isReserved(char c) {
return isGenericDelimiter(c) || isReserved(c);
}
protected boolean isUnreserved(int c) {
return isAlpha(c) || isDigit(c) || '-' == c || '.' == c || '_' == c || '~' == c;
}
protected boolean isPchar(int c) {
return isUnreserved(c) || isSubDelimiter(c) || ':' == c || '@' == c;
}
}
/** The scheme URI component. */
public static final UriComponent SCHEME_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isAlpha(c) || isDigit(c) || '+' == c || '-' == c || '.' == c;
}
};
/** The authority URI component. */
public static final UriComponent AUTHORITY_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isUnreserved(c) || isSubDelimiter(c) || ':' == c || '@' == c;
}
};
/** The user info URI component. */
public static final UriComponent USER_INFO_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isUnreserved(c) || isSubDelimiter(c) || ':' == c;
}
};
/** The host URI component. */
public static final UriComponent HOST_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isUnreserved(c) || isSubDelimiter(c);
}
};
/** The port URI component. */
public static final UriComponent PORT_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isDigit(c);
}
};
/** The path URI component. */
public static final UriComponent PATH_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isPchar(c) || '/' == c;
}
};
/** The path segment URI component. */
public static final UriComponent PATH_SEGMENT_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isPchar(c);
}
};
/** The query URI component. */
public static final UriComponent QUERY_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isPchar(c) || '/' == c || '?' == c;
}
};
/** The query parameter URI component. */
public static final UriComponent QUERY_PARAM_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
if ('=' == c || '+' == c || '&' == c) {
return false;
}
else {
return isPchar(c) || '/' == c || '?' == c;
}
}
};
/** The fragment URI component. */
public static final UriComponent FRAGMENT_COMPONENT = new AbstractUriComponent() {
public boolean isAllowed(int c) {
return isPchar(c) || '/' == c || '?' == c;
}
};
}

8
org.springframework.web/src/test/java/org/springframework/web/util/UriBuilderTests.java

@ -38,6 +38,14 @@ public class UriBuilderTests { @@ -38,6 +38,14 @@ public class UriBuilderTests {
assertEquals("Invalid result URI", expected, result);
}
@Test
public void fromPath() throws URISyntaxException {
URI result = UriBuilder.fromPath("foo").queryParam("bar").fragment("baz").build();
URI expected = new URI("/foo?bar#baz");
assertEquals("Invalid result URI", expected, result);
}
@Test
public void fromUri() throws URISyntaxException {
URI uri = new URI("http://example.com/foo?bar#baz");

Loading…
Cancel
Save