diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java
index 3cf2d29f04..2aadbbee86 100644
--- a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java
+++ b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java
@@ -69,7 +69,7 @@ class DefaultRequestPath implements RequestPath {
counter += ((Segment) element).semicolonContent().length();
}
if (length == counter) {
- return DefaultPathContainer.subPath(path, 0, i + 1);
+ return path.subPath(0, i + 1);
}
}
@@ -79,7 +79,7 @@ class DefaultRequestPath implements RequestPath {
}
private static PathContainer extractPathWithinApplication(PathContainer fullPath, PathContainer contextPath) {
- return PathContainer.subPath(fullPath, contextPath.elements().size());
+ return fullPath.subPath(contextPath.elements().size());
}
diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java b/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java
index c6d00dc4eb..88045eed40 100644
--- a/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java
+++ b/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java
@@ -22,16 +22,21 @@ import java.util.List;
import org.springframework.util.MultiValueMap;
/**
- * Structured path representation.
+ * Structured representation of a path whose {@link Element Elements} are
+ * accessible as a sequence of either {@link Separator Separator} and/or
+ * {@link Segment Segment} (element) types.
*
- *
Typically consumed via {@link ServerHttpRequest#getPath()} but can also
- * be created by parsing a path value via {@link #parse(String, Charset)}.
+ *
Each {@code Segment} exposes its own structure decoded safely without the
+ * risk of encoded reserved characters altering the path or segment structure.
+ *
+ *
An instance of this class can also be created via
+ * {@link #parse(String, Charset)}. The path for an HTTP request is parsed once
+ * and subsequently accessible via {@link ServerHttpRequest#getPath()}.
*
* @author Rossen Stoyanchev
*/
public interface PathContainer {
-
/**
* The original, raw (encoded) path value including path parameters.
*/
@@ -42,6 +47,26 @@ public interface PathContainer {
*/
List elements();
+ /**
+ * Extract a sub-path from the given offset into the elements list.
+ * @param index the start element index (inclusive)
+ * @return the sub-path
+ */
+ default PathContainer subPath(int index) {
+ return subPath(index, elements().size());
+ }
+
+ /**
+ * Extract a sub-path from the given start offset (inclusive) into the
+ * element list and to the end offset (exclusive).
+ * @param startIndex the start element index (inclusive)
+ * @param endIndex the end element index (exclusive)
+ * @return the sub-path
+ */
+ default PathContainer subPath(int startIndex, int endIndex) {
+ return DefaultPathContainer.subPath(this, startIndex, endIndex);
+ }
+
/**
* Parse the given path value into a {@link PathContainer}.
@@ -53,29 +78,10 @@ public interface PathContainer {
return DefaultPathContainer.parsePath(path, encoding);
}
- /**
- * Extract a sub-path from the given offset into the path elements list.
- * @param path the path to extract from
- * @param index the start element index (inclusive)
- * @return the sub-path
- */
- static PathContainer subPath(PathContainer path, int index) {
- return subPath(path, index, path.elements().size());
- }
/**
- * Extract a sub-path from the given start offset (inclusive) into the path
- * element list and to the end offset (exclusive).
- * @param path the path to extract from
- * @param startIndex the start element index (inclusive)
- * @param endIndex the end element index (exclusive)
- * @return the sub-path
+ * Common representation of a path element, e.g. separator or segment.
*/
- static PathContainer subPath(PathContainer path, int startIndex, int endIndex) {
- return DefaultPathContainer.subPath(path, startIndex, endIndex);
- }
-
-
interface Element {
/**
@@ -86,14 +92,14 @@ public interface PathContainer {
/**
- * A path separator element.
+ * Path separator element.
*/
interface Separator extends Element {
}
/**
- * A path segment element.
+ * Path segment element.
*/
interface Segment extends Element {
diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java
index 3e103fa0cf..51ff839eee 100644
--- a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java
+++ b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java
@@ -205,7 +205,7 @@ public class PathPattern implements Comparable {
info = new PathRemainingMatchInfo(EMPTY_PATH, matchingContext.getPathMatchResult());
}
else {
- info = new PathRemainingMatchInfo(PathContainer.subPath(pathContainer, matchingContext.remainingPathIndex),
+ info = new PathRemainingMatchInfo(pathContainer.subPath(matchingContext.remainingPathIndex),
matchingContext.getPathMatchResult());
}
return info;
diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/DefaultPathContainerTests.java b/spring-web/src/test/java/org/springframework/http/server/reactive/DefaultPathContainerTests.java
index 3905478157..dab1a246ad 100644
--- a/spring-web/src/test/java/org/springframework/http/server/reactive/DefaultPathContainerTests.java
+++ b/spring-web/src/test/java/org/springframework/http/server/reactive/DefaultPathContainerTests.java
@@ -127,17 +127,17 @@ public class DefaultPathContainerTests {
public void subPath() throws Exception {
// basic
PathContainer path = PathContainer.parse("/a/b/c", UTF_8);
- assertSame(path, PathContainer.subPath(path, 0));
- assertEquals("/b/c", PathContainer.subPath(path, 2).value());
- assertEquals("/c", PathContainer.subPath(path, 4).value());
+ assertSame(path, path.subPath(0));
+ assertEquals("/b/c", path.subPath(2).value());
+ assertEquals("/c", path.subPath(4).value());
// root path
path = PathContainer.parse("/", UTF_8);
- assertEquals("/", PathContainer.subPath(path, 0).value());
+ assertEquals("/", path.subPath(0).value());
// trailing slash
path = PathContainer.parse("/a/b/", UTF_8);
- assertEquals("/b/", PathContainer.subPath(path, 2).value());
+ assertEquals("/b/", path.subPath(2).value());
}
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java
index 536d76901f..8542c0e336 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java
@@ -215,7 +215,7 @@ public class ResourceUrlProvider implements ApplicationListener {
PathContainer path = entry.getKey().extractPathWithinPattern(lookupPath);
int endIndex = lookupPath.elements().size() - path.elements().size();
- PathContainer mapping = PathContainer.subPath(lookupPath, 0, endIndex);
+ PathContainer mapping = lookupPath.subPath(0, endIndex);
if (logger.isTraceEnabled()) {
logger.trace("Invoking ResourceResolverChain for URL pattern " +
"\"" + entry.getKey() + "\"");