Revisit EndpointRequest matcher for additional paths

Prior to this commit, the `EndpointRequest` request matcher generator
would create many, complex matchers for the case of health groups
exposed on additional paths.

This commit revisits the matcher generation and simplifies their
matching to avoid conflicts with other matchers.

Fixes gh-49648
This commit is contained in:
Brian Clozel
2026-03-18 17:35:22 +01:00
parent 01fbede2b2
commit 1f2ea4a6db
4 changed files with 8 additions and 7 deletions
@@ -441,12 +441,12 @@ public final class EndpointRequest {
@Override
protected ServerWebExchangeMatcher createDelegate(PathMappedEndpoints endpoints) {
Set<String> paths = this.endpoints.stream()
List<ServerWebExchangeMatcher> delegateMatchers = this.endpoints.stream()
.filter(Objects::nonNull)
.map(this::getEndpointId)
.flatMap((endpointId) -> streamAdditionalPaths(endpoints, endpointId))
.collect(Collectors.toCollection(LinkedHashSet::new));
List<ServerWebExchangeMatcher> delegateMatchers = getDelegateMatchers(paths, this.httpMethod);
.map(PathPatternParserServerWebExchangeMatcher::new)
.collect(Collectors.toCollection(ArrayList::new));
return (!CollectionUtils.isEmpty(delegateMatchers)) ? new OrServerWebExchangeMatcher(delegateMatchers)
: EMPTY_MATCHER;
}
@@ -475,13 +475,12 @@ public final class EndpointRequest {
RequestMatcherFactory requestMatcherFactory) {
PathMappedEndpoints endpoints = context.getBean(PathMappedEndpoints.class);
RequestMatcherProvider matcherProvider = getRequestMatcherProvider(context);
Set<String> paths = this.endpoints.stream()
List<RequestMatcher> delegateMatchers = this.endpoints.stream()
.filter(Objects::nonNull)
.map(this::getEndpointId)
.flatMap((endpointId) -> streamAdditionalPaths(endpoints, endpointId))
.collect(Collectors.toCollection(LinkedHashSet::new));
List<RequestMatcher> delegateMatchers = getDelegateMatchers(requestMatcherFactory, matcherProvider, paths,
this.httpMethod);
.map((path) -> requestMatcherFactory.antPath(matcherProvider, this.httpMethod, path))
.collect(Collectors.toCollection(ArrayList::new));
return (!CollectionUtils.isEmpty(delegateMatchers)) ? new OrRequestMatcher(delegateMatchers)
: EMPTY_MATCHER;
}
@@ -315,6 +315,7 @@ class EndpointRequestTests {
FooEndpoint.class);
RequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints("",
() -> List.of(mockEndpoint(EndpointId.of("foo"), "test", WebServerNamespace.SERVER, "/additional"))));
assertMatcher.doesNotMatch("/additional/foo");
assertMatcher.doesNotMatch("/foo");
assertMatcher.doesNotMatch("/bar");
}
@@ -321,6 +321,7 @@ class EndpointRequestTests {
FooEndpoint.class);
RequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints("",
() -> List.of(mockEndpoint(EndpointId.of("foo"), "test", WebServerNamespace.SERVER, "/additional"))));
assertMatcher.doesNotMatch("/additional/foo");
assertMatcher.doesNotMatch("/foo");
assertMatcher.doesNotMatch("/bar");
}