diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/UriBuilder.java b/org.springframework.web/src/main/java/org/springframework/web/util/UriBuilder.java index ec620c8ed6..f2e0b7364d 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/util/UriBuilder.java +++ b/org.springframework.web/src/main/java/org/springframework/web/util/UriBuilder.java @@ -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. + * *
Inspired by {@link javax.ws.rs.core.UriBuilder}. * * @author Arjen Poutsma @@ -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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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; diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/UriComponent.java b/org.springframework.web/src/main/java/org/springframework/web/util/UriComponent.java new file mode 100644 index 0000000000..c54a12ce5e --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/util/UriComponent.java @@ -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. + * + *
Contains methods to indicate whether a given character is valid in a specific URI component.
+ *
+ * @author Arjen Poutsma
+ * @see RFC 3986
+ * @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 RFC 3986, appendix 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 RFC 3986, appendix A
+ */
+ protected boolean isDigit(int c) {
+ return c >= '0' && c <= '9';
+ }
+
+ /**
+ * Indicates whether the given character is in the {@code gen-delims} set.
+ *
+ * @see RFC 3986, appendix 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 RFC 3986, appendix 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 RFC 3986, appendix A
+ */
+ protected boolean isReserved(char c) {
+ return isGenericDelimiter(c) || isReserved(c);
+ }
+
+ /**
+ * Indicates whether the given character is in the {@code unreserved} set.
+ *
+ * @see RFC 3986, appendix 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 RFC 3986, appendix A
+ */
+ protected boolean isPchar(int c) {
+ return isUnreserved(c) || isSubDelimiter(c) || ':' == c || '@' == c;
+ }
+
+}
diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/UriTemplate.java b/org.springframework.web/src/main/java/org/springframework/web/util/UriTemplate.java
index 513d2e31db..51ebb22460 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/util/UriTemplate.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/util/UriTemplate.java
@@ -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 {
* 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 {
* or if it does not contain values for all the variable names
*/
public URI expand(Map