diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPatternParser.java b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPatternParser.java
index 9bac52b388e..30ff6ff55c5 100644
--- a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPatternParser.java
+++ b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPatternParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -17,6 +17,7 @@
package org.springframework.web.util.pattern;
import org.springframework.http.server.PathContainer;
+import org.springframework.util.StringUtils;
/**
* Parser for URI path patterns producing {@link PathPattern} instances that can
@@ -103,6 +104,17 @@ public class PathPatternParser {
}
+ /**
+ * Prepare the given pattern for use in matching to full URL paths.
+ *
By default, prepend a leading slash if needed for non-empty patterns.
+ * @param pattern the pattern to initialize
+ * @return the updated pattern
+ * @since 5.2.25
+ */
+ public String initFullPathPattern(String pattern) {
+ return (StringUtils.hasLength(pattern) && !pattern.startsWith("/") ? "/" + pattern : pattern);
+ }
+
/**
* Process the path pattern content, a character at a time, breaking it into
* path elements around separator boundaries and verifying the structure at each
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java
index 003c1571eb1..c43bfbb1f55 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -110,10 +110,9 @@ public abstract class RequestPredicates {
*/
public static RequestPredicate path(String pattern) {
Assert.notNull(pattern, "'pattern' must not be null");
- if (!pattern.isEmpty() && !pattern.startsWith("/")) {
- pattern = "/" + pattern;
- }
- return pathPredicates(PathPatternParser.defaultInstance).apply(pattern);
+ PathPatternParser parser = PathPatternParser.defaultInstance;
+ pattern = parser.initFullPathPattern(pattern);
+ return pathPredicates(parser).apply(pattern);
}
/**
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
index a4997b3ab8f..71eb1865f0b 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
@@ -29,10 +29,10 @@ import org.springframework.beans.BeansException;
import org.springframework.http.server.PathContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
-import org.springframework.util.StringUtils;
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
+import org.springframework.web.util.pattern.PathPatternParser;
/**
* Abstract base class for URL-mapped
@@ -213,8 +213,9 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
Object resolvedHandler = handler;
// Parse path pattern
- urlPath = prependLeadingSlash(urlPath);
- PathPattern pattern = getPathPatternParser().parse(urlPath);
+ PathPatternParser parser = getPathPatternParser();
+ urlPath = parser.initFullPathPattern(urlPath);
+ PathPattern pattern = parser.parse(urlPath);
if (this.handlerMap.containsKey(pattern)) {
Object existingHandler = this.handlerMap.get(pattern);
if (existingHandler != null && existingHandler != resolvedHandler) {
@@ -242,14 +243,4 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
return (handler instanceof String ? "'" + handler + "'" : handler.toString());
}
-
- private static String prependLeadingSlash(String pattern) {
- if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
- return "/" + pattern;
- }
- else {
- return pattern;
- }
- }
-
}
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 8f3e3b0bbf0..765e021fc68 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -35,7 +35,6 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
-import org.springframework.util.StringUtils;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
@@ -86,8 +85,9 @@ public class ResourceUrlProvider implements ApplicationListener handlerMap) {
this.handlerMap.clear();
handlerMap.forEach((rawPattern, resourceWebHandler) -> {
- rawPattern = prependLeadingSlash(rawPattern);
- PathPattern pattern = PathPatternParser.defaultInstance.parse(rawPattern);
+ PathPatternParser parser = PathPatternParser.defaultInstance;
+ rawPattern = parser.initFullPathPattern(rawPattern);
+ PathPattern pattern = parser.parse(rawPattern);
this.handlerMap.put(pattern, resourceWebHandler);
});
}
@@ -172,14 +172,4 @@ public class ResourceUrlProvider implements ApplicationListener result = new ArrayList<>(patterns.length);
- for (String path : patterns) {
- if (StringUtils.hasText(path) && !path.startsWith("/")) {
- path = "/" + path;
- }
- result.add(parser.parse(path));
+ for (String pattern : patterns) {
+ pattern = parser.initFullPathPattern(pattern);
+ result.add(parser.parse(pattern));
}
return result;
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java
index 08606f5c01f..b71277ed16d 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -109,10 +109,9 @@ public abstract class RequestPredicates {
*/
public static RequestPredicate path(String pattern) {
Assert.notNull(pattern, "'pattern' must not be null");
- if (!pattern.isEmpty() && !pattern.startsWith("/")) {
- pattern = "/" + pattern;
- }
- return pathPredicates(PathPatternParser.defaultInstance).apply(pattern);
+ PathPatternParser parser = PathPatternParser.defaultInstance;
+ pattern = parser.initFullPathPattern(pattern);
+ return pathPredicates(parser).apply(pattern);
}
/**
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java
index 623c42d8e34..6c194b88d83 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java
@@ -51,6 +51,7 @@ import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.ServletRequestPathUtils;
import org.springframework.web.util.UrlPathHelper;
+import org.springframework.web.util.pattern.PathPatternParser;
/**
* Helper class to get information from the {@code HandlerMapping} that would
@@ -309,10 +310,15 @@ public class HandlerMappingIntrospector
ServletRequestPathUtils.PATH_ATTRIBUTE : UrlPathHelper.PATH_ATTRIBUTE);
}
+ @Override
+ public PathPatternParser getPatternParser() {
+ return this.delegate.getPatternParser();
+ }
+
@Nullable
@Override
public RequestMatchResult match(HttpServletRequest request, String pattern) {
- pattern = (StringUtils.hasLength(pattern) && !pattern.startsWith("/") ? "/" + pattern : pattern);
+ pattern = initFullPathPattern(pattern);
Object previousPath = request.getAttribute(this.pathAttributeName);
request.setAttribute(this.pathAttributeName, this.lookupPath);
try {
@@ -323,6 +329,11 @@ public class HandlerMappingIntrospector
}
}
+ private String initFullPathPattern(String pattern) {
+ PathPatternParser parser = (getPatternParser() != null ? getPatternParser() : PathPatternParser.defaultInstance);
+ return parser.initFullPathPattern(pattern);
+ }
+
@Nullable
@Override
public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PathPatternsRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PathPatternsRequestCondition.java
index 93e9033fa8c..091ea4e53a5 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PathPatternsRequestCondition.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PathPatternsRequestCondition.java
@@ -79,11 +79,9 @@ public final class PathPatternsRequestCondition extends AbstractRequestCondition
return EMPTY_PATH_PATTERN;
}
SortedSet result = new TreeSet<>();
- for (String path : patterns) {
- if (StringUtils.hasText(path) && !path.startsWith("/")) {
- path = "/" + path;
- }
- result.add(parser.parse(path));
+ for (String pattern : patterns) {
+ pattern = parser.initFullPathPattern(pattern);
+ result.add(parser.parse(pattern));
}
return result;
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java
index f9b69ffbdb3..ea28749fe6a 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java
@@ -35,6 +35,7 @@ import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.pattern.PathPattern;
+import org.springframework.web.util.pattern.PathPatternParser;
/**
* A logical disjunction (' || ') request condition that matches a request
@@ -158,9 +159,7 @@ public class PatternsRequestCondition extends AbstractRequestCondition result = new LinkedHashSet<>(patterns.length);
for (String pattern : patterns) {
- if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
- pattern = "/" + pattern;
- }
+ pattern = PathPatternParser.defaultInstance.initFullPathPattern(pattern);
result.add(pattern);
}
return result;
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java
index 839b51d51d3..ecaa081426a 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java
@@ -64,6 +64,7 @@ import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
+import org.springframework.web.util.pattern.PathPatternParser;
/**
* Creates instances of {@link org.springframework.web.util.UriComponentsBuilder}
@@ -544,10 +545,8 @@ public class MvcUriComponentsBuilder {
String typePath = getClassMapping(controllerType);
String methodPath = getMethodMapping(method);
String path = pathMatcher.combine(typePath, methodPath);
- if (StringUtils.hasLength(path) && !path.startsWith("/")) {
- path = "/" + path;
- }
- else if (!StringUtils.hasText(prefix + path)) {
+ path = PathPatternParser.defaultInstance.initFullPathPattern(path);
+ if (!StringUtils.hasText(prefix + path)) {
path = "/";
}
builder.path(path);