Skip to content

Commit 7c56a45

Browse files
committed
Drop support for String path matching for MVC endpoints
Closes gh-31700
1 parent 92c530c commit 7c56a45

File tree

7 files changed

+10
-124
lines changed

7 files changed

+10
-124
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
6363
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
6464
CorsConfiguration corsConfiguration, CloudFoundrySecurityInterceptor securityInterceptor,
6565
EndpointLinksResolver linksResolver) {
66-
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true,
67-
AbstractWebMvcEndpointHandlerMapping.pathPatternParser);
66+
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true);
6867
this.securityInterceptor = securityInterceptor;
6968
this.linksResolver = linksResolver;
7069
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/servlet/WebMvcEndpointManagementContextConfiguration.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
3838
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
3939
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
40-
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
4140
import org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
4241
import org.springframework.boot.actuate.endpoint.web.servlet.ControllerEndpointHandlerMapping;
4342
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
@@ -85,7 +84,7 @@ public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpoint
8584
boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
8685
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
8786
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
88-
shouldRegisterLinksMapping, AbstractWebMvcEndpointHandlerMapping.pathPatternParser);
87+
shouldRegisterLinksMapping);
8988
}
9089

9190
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebMvcEndpointIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint;
3333
import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
3434
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
35-
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
3635
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
3736
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
3837
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
@@ -56,6 +55,7 @@
5655
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
5756
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
5857
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
58+
import org.springframework.web.util.pattern.PathPatternParser;
5959

6060
import static org.assertj.core.api.Assertions.assertThat;
6161
import static org.hamcrest.Matchers.both;
@@ -87,7 +87,7 @@ void webMvcEndpointHandlerMappingIsConfiguredWithPathPatternParser() {
8787
this.context.setServletContext(new MockServletContext());
8888
this.context.refresh();
8989
WebMvcEndpointHandlerMapping handlerMapping = this.context.getBean(WebMvcEndpointHandlerMapping.class);
90-
assertThat(handlerMapping.getPatternParser()).isEqualTo(AbstractWebMvcEndpointHandlerMapping.pathPatternParser);
90+
assertThat(handlerMapping.getPatternParser()).isInstanceOf(PathPatternParser.class);
9191
}
9292

9393
@Test

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMapping.java

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.util.LinkedHashMap;
2727
import java.util.List;
2828
import java.util.Map;
29-
import java.util.Set;
3029
import java.util.function.Function;
3130

3231
import jakarta.servlet.http.HttpServletRequest;
@@ -68,11 +67,8 @@
6867
import org.springframework.web.method.HandlerMethod;
6968
import org.springframework.web.server.ResponseStatusException;
7069
import org.springframework.web.servlet.HandlerMapping;
71-
import org.springframework.web.servlet.handler.MatchableHandlerMapping;
72-
import org.springframework.web.servlet.handler.RequestMatchResult;
7370
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
7471
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
75-
import org.springframework.web.util.pattern.PathPatternParser;
7672

7773
/**
7874
* A custom {@link HandlerMapping} that makes {@link ExposableWebEndpoint web endpoints}
@@ -85,7 +81,7 @@
8581
* @since 2.0.0
8682
*/
8783
public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappingInfoHandlerMapping
88-
implements InitializingBean, MatchableHandlerMapping {
84+
implements InitializingBean {
8985

9086
private final EndpointMapping endpointMapping;
9187

@@ -102,11 +98,6 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
10298

10399
private RequestMappingInfo.BuilderConfiguration builderConfig = new RequestMappingInfo.BuilderConfiguration();
104100

105-
/**
106-
* Instance of {@link PathPatternParser} shared across actuator configuration.
107-
*/
108-
public static final PathPatternParser pathPatternParser = new PathPatternParser();
109-
110101
/**
111102
* Creates a new {@code WebEndpointHandlerMapping} that provides mappings for the
112103
* operations of the given {@code webEndpoints}.
@@ -133,45 +124,19 @@ public AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
133124
public AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
134125
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
135126
CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping) {
136-
this(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, shouldRegisterLinksMapping, null);
137-
}
138-
139-
/**
140-
* Creates a new {@code AbstractWebMvcEndpointHandlerMapping} that provides mappings
141-
* for the operations of the given endpoints.
142-
* @param endpointMapping the base mapping for all endpoints
143-
* @param endpoints the web endpoints
144-
* @param endpointMediaTypes media types consumed and produced by the endpoints
145-
* @param corsConfiguration the CORS configuration for the endpoints or {@code null}
146-
* @param shouldRegisterLinksMapping whether the links endpoint should be registered
147-
* @param pathPatternParser the path pattern parser
148-
*/
149-
public AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
150-
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
151-
CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping,
152-
PathPatternParser pathPatternParser) {
153127
this.endpointMapping = endpointMapping;
154128
this.endpoints = endpoints;
155129
this.endpointMediaTypes = endpointMediaTypes;
156130
this.corsConfiguration = corsConfiguration;
157131
this.shouldRegisterLinksMapping = shouldRegisterLinksMapping;
158-
setPatternParser(pathPatternParser);
159132
setOrder(-100);
160133
}
161134

162135
@Override
163136
@SuppressWarnings("deprecation")
164137
public void afterPropertiesSet() {
165138
this.builderConfig = new RequestMappingInfo.BuilderConfiguration();
166-
if (getPatternParser() != null) {
167-
this.builderConfig.setPatternParser(getPatternParser());
168-
}
169-
else {
170-
this.builderConfig.setPathMatcher(null);
171-
this.builderConfig.setTrailingSlashMatch(true);
172-
this.builderConfig.setSuffixPatternMatch(false);
173-
174-
}
139+
this.builderConfig.setPatternParser(getPatternParser());
175140
super.afterPropertiesSet();
176141
}
177142

@@ -193,19 +158,6 @@ protected HandlerMethod createHandlerMethod(Object handler, Method method) {
193158
return new WebMvcEndpointHandlerMethod(handlerMethod.getBean(), handlerMethod.getMethod());
194159
}
195160

196-
@Override
197-
public RequestMatchResult match(HttpServletRequest request, String pattern) {
198-
Assert.isNull(getPatternParser(), "This HandlerMapping uses PathPatterns.");
199-
RequestMappingInfo info = RequestMappingInfo.paths(pattern).options(this.builderConfig).build();
200-
RequestMappingInfo matchingInfo = info.getMatchingCondition(request);
201-
if (matchingInfo == null) {
202-
return null;
203-
}
204-
Set<String> patterns = matchingInfo.getPatternsCondition().getPatterns();
205-
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
206-
return new RequestMatchResult(patterns.iterator().next(), lookupPath, getPathMatcher());
207-
}
208-
209161
private void registerMappingForOperation(ExposableWebEndpoint endpoint, WebOperation operation) {
210162
WebOperationRequestPredicate predicate = operation.getRequestPredicate();
211163
String path = predicate.getPath();

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/ControllerEndpointHandlerMapping.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ public ControllerEndpointHandlerMapping(EndpointMapping endpointMapping,
6767
this.handlers = getHandlers(endpoints);
6868
this.corsConfiguration = corsConfiguration;
6969
setOrder(-100);
70-
setUseSuffixPatternMatch(false);
7170
}
7271

7372
private Map<Object, ExposableControllerEndpoint> getHandlers(Collection<ExposableControllerEndpoint> endpoints) {

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMapping.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.springframework.web.bind.annotation.ResponseBody;
3232
import org.springframework.web.cors.CorsConfiguration;
3333
import org.springframework.web.servlet.HandlerMapping;
34-
import org.springframework.web.util.pattern.PathPatternParser;
3534

3635
/**
3736
* A custom {@link HandlerMapping} that makes web endpoints available over HTTP using
@@ -63,27 +62,6 @@ public WebMvcEndpointHandlerMapping(EndpointMapping endpointMapping, Collection<
6362
setOrder(-100);
6463
}
6564

66-
/**
67-
* Creates a new {@code WebMvcEndpointHandlerMapping} instance that provides mappings
68-
* for the given endpoints.
69-
* @param endpointMapping the base mapping for all endpoints
70-
* @param endpoints the web endpoints
71-
* @param endpointMediaTypes media types consumed and produced by the endpoints
72-
* @param corsConfiguration the CORS configuration for the endpoints or {@code null}
73-
* @param linksResolver resolver for determining links to available endpoints
74-
* @param shouldRegisterLinksMapping whether the links endpoint should be registered
75-
* @param pathPatternParser the path pattern parser
76-
*/
77-
public WebMvcEndpointHandlerMapping(EndpointMapping endpointMapping, Collection<ExposableWebEndpoint> endpoints,
78-
EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration,
79-
EndpointLinksResolver linksResolver, boolean shouldRegisterLinksMapping,
80-
PathPatternParser pathPatternParser) {
81-
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, shouldRegisterLinksMapping,
82-
pathPatternParser);
83-
this.linksResolver = linksResolver;
84-
setOrder(-100);
85-
}
86-
8765
@Override
8866
protected LinksHandler getLinksHandler() {
8967
return new WebMvcLinksHandler();

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/MvcWebEndpointIntegrationTests.java

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import org.springframework.core.env.Environment;
4646
import org.springframework.http.HttpStatus;
4747
import org.springframework.http.MediaType;
48-
import org.springframework.mock.web.MockHttpServletRequest;
4948
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
5049
import org.springframework.security.core.authority.SimpleGrantedAuthority;
5150
import org.springframework.security.core.context.SecurityContext;
@@ -54,12 +53,8 @@
5453
import org.springframework.util.StringUtils;
5554
import org.springframework.web.cors.CorsConfiguration;
5655
import org.springframework.web.filter.OncePerRequestFilter;
57-
import org.springframework.web.servlet.handler.RequestMatchResult;
58-
import org.springframework.web.util.ServletRequestPathUtils;
59-
import org.springframework.web.util.pattern.PathPatternParser;
6056

6157
import static org.assertj.core.api.Assertions.assertThat;
62-
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
6358

6459
/**
6560
* Integration tests for web endpoints exposed using Spring MVC.
@@ -107,44 +102,9 @@ void readOperationsThatReturnAResourceSupportRangeRequests() {
107102
}
108103

109104
@Test
110-
void matchWhenPathPatternParserShouldThrowException() {
111-
assertThatIllegalArgumentException().isThrownBy(() -> getMatchResult("/spring/", true));
112-
}
113-
114-
@Test
115-
void matchWhenRequestHasTrailingSlashShouldNotBeNull() {
116-
assertThat(getMatchResult("/spring/", false)).isNotNull();
117-
}
118-
119-
@Test
120-
void matchWhenRequestHasSuffixShouldBeNull() {
121-
assertThat(getMatchResult("/spring.do", false)).isNull();
122-
}
123-
124-
private RequestMatchResult getMatchResult(String servletPath, boolean isPatternParser) {
125-
MockHttpServletRequest request = new MockHttpServletRequest();
126-
request.setServletPath(servletPath);
127-
try (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext()) {
128-
if (isPatternParser) {
129-
context.register(WebMvcConfiguration.class);
130-
}
131-
else {
132-
context.register(PathMatcherWebMvcConfiguration.class);
133-
}
134-
context.register(TestEndpointConfiguration.class);
135-
context.refresh();
136-
WebMvcEndpointHandlerMapping bean = context.getBean(WebMvcEndpointHandlerMapping.class);
137-
try {
138-
// Setup request attributes
139-
ServletRequestPathUtils.parseAndCache(request);
140-
// Trigger initLookupPath
141-
bean.getHandler(request);
142-
}
143-
catch (Exception ex) {
144-
throw new RuntimeException(ex);
145-
}
146-
return bean.match(request, "/spring");
147-
}
105+
void requestWithSuffixShouldNotMatch() {
106+
load(TestEndpointConfiguration.class, (client) -> client.options().uri("/test.do")
107+
.accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isNotFound());
148108
}
149109

150110
@Override
@@ -172,8 +132,7 @@ WebMvcEndpointHandlerMapping webEndpointHandlerMapping(Environment environment,
172132
String endpointPath = environment.getProperty("endpointPath");
173133
return new WebMvcEndpointHandlerMapping(new EndpointMapping(endpointPath),
174134
endpointDiscoverer.getEndpoints(), endpointMediaTypes, corsConfiguration,
175-
new EndpointLinksResolver(endpointDiscoverer.getEndpoints()), StringUtils.hasText(endpointPath),
176-
new PathPatternParser());
135+
new EndpointLinksResolver(endpointDiscoverer.getEndpoints()), StringUtils.hasText(endpointPath));
177136
}
178137

179138
}

0 commit comments

Comments
 (0)