Skip to content

Commit 6b2a27d

Browse files
committed
Mappings Endpoint support mvc router funtion
1 parent 33aa8f7 commit 6b2a27d

File tree

9 files changed

+519
-54
lines changed

9 files changed

+519
-54
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlerMappingDescription.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.boot.actuate.web.mappings.reactive;
1818

19+
import java.util.List;
20+
1921
import org.springframework.web.servlet.DispatcherServlet;
2022

2123
/**
@@ -30,12 +32,22 @@ public class DispatcherHandlerMappingDescription {
3032

3133
private final String handler;
3234

35+
private final List<DispatcherHandlerMappingDescription> children;
36+
3337
private final DispatcherHandlerMappingDetails details;
3438

39+
DispatcherHandlerMappingDescription(String predicate, String handler, DispatcherHandlerMappingDetails details, List<DispatcherHandlerMappingDescription> children) {
40+
this.predicate = predicate;
41+
this.handler = handler;
42+
this.details = details;
43+
this.children = children;
44+
}
45+
3546
DispatcherHandlerMappingDescription(String predicate, String handler, DispatcherHandlerMappingDetails details) {
3647
this.predicate = predicate;
3748
this.handler = handler;
3849
this.details = details;
50+
this.children = null;
3951
}
4052

4153
public String getHandler() {
@@ -46,6 +58,10 @@ public String getPredicate() {
4658
return this.predicate;
4759
}
4860

61+
public List<DispatcherHandlerMappingDescription> getChildren() {
62+
return this.children;
63+
}
64+
4965
public DispatcherHandlerMappingDetails getDetails() {
5066
return this.details;
5167
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProvider.java

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,16 +16,13 @@
1616

1717
package org.springframework.boot.actuate.web.mappings.reactive;
1818

19-
import java.util.ArrayList;
2019
import java.util.Arrays;
2120
import java.util.HashMap;
2221
import java.util.List;
2322
import java.util.Map;
2423
import java.util.Map.Entry;
25-
import java.util.function.Function;
2624
import java.util.stream.Stream;
2725

28-
import reactor.core.publisher.Mono;
2926

3027
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
3128
import org.springframework.aot.hint.RuntimeHints;
@@ -35,15 +32,10 @@
3532
import org.springframework.boot.actuate.web.mappings.reactive.DispatcherHandlersMappingDescriptionProvider.DispatcherHandlersMappingDescriptionProviderRuntimeHints;
3633
import org.springframework.context.ApplicationContext;
3734
import org.springframework.context.annotation.ImportRuntimeHints;
38-
import org.springframework.core.io.Resource;
3935
import org.springframework.web.method.HandlerMethod;
4036
import org.springframework.web.reactive.DispatcherHandler;
4137
import org.springframework.web.reactive.HandlerMapping;
42-
import org.springframework.web.reactive.function.server.HandlerFunction;
43-
import org.springframework.web.reactive.function.server.RequestPredicate;
4438
import org.springframework.web.reactive.function.server.RouterFunction;
45-
import org.springframework.web.reactive.function.server.RouterFunctions.Visitor;
46-
import org.springframework.web.reactive.function.server.ServerRequest;
4739
import org.springframework.web.reactive.function.server.support.RouterFunctionMapping;
4840
import org.springframework.web.reactive.handler.AbstractUrlHandlerMapping;
4941
import org.springframework.web.reactive.result.method.RequestMappingInfo;
@@ -158,41 +150,7 @@ public List<DispatcherHandlerMappingDescription> describe(RouterFunctionMapping
158150
if (routerFunction != null) {
159151
routerFunction.accept(visitor);
160152
}
161-
return visitor.descriptions;
162-
}
163-
164-
}
165-
166-
private static final class MappingDescriptionVisitor implements Visitor {
167-
168-
private final List<DispatcherHandlerMappingDescription> descriptions = new ArrayList<>();
169-
170-
@Override
171-
public void startNested(RequestPredicate predicate) {
172-
}
173-
174-
@Override
175-
public void endNested(RequestPredicate predicate) {
176-
}
177-
178-
@Override
179-
public void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction) {
180-
DispatcherHandlerMappingDetails details = new DispatcherHandlerMappingDetails();
181-
details.setHandlerFunction(new HandlerFunctionDescription(handlerFunction));
182-
this.descriptions.add(
183-
new DispatcherHandlerMappingDescription(predicate.toString(), handlerFunction.toString(), details));
184-
}
185-
186-
@Override
187-
public void resources(Function<ServerRequest, Mono<Resource>> lookupFunction) {
188-
}
189-
190-
@Override
191-
public void attributes(Map<String, Object> attributes) {
192-
}
193-
194-
@Override
195-
public void unknown(RouterFunction<?> routerFunction) {
153+
return visitor.getDescriptions();
196154
}
197155

198156
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.web.mappings.reactive;
18+
19+
20+
import org.springframework.core.io.Resource;
21+
import org.springframework.http.HttpMethod;
22+
import org.springframework.web.reactive.function.server.HandlerFunction;
23+
import org.springframework.web.reactive.function.server.RequestPredicate;
24+
import org.springframework.web.reactive.function.server.RequestPredicates;
25+
import org.springframework.web.reactive.function.server.RouterFunction;
26+
import org.springframework.web.reactive.function.server.RouterFunctions;
27+
import org.springframework.web.reactive.function.server.ServerRequest;
28+
29+
30+
import java.util.ArrayDeque;
31+
import java.util.ArrayList;
32+
import java.util.Deque;
33+
import java.util.List;
34+
import java.util.Map;
35+
import java.util.Set;
36+
import java.util.Stack;
37+
import java.util.function.Function;
38+
39+
import reactor.core.publisher.Mono;
40+
41+
42+
/**
43+
* A Visitor that builds a list of {@link DispatcherHandlerMappingDescription DispatcherHandlerMappingDescriptions}
44+
* @since 3.5.0
45+
* @author Xiong Tang
46+
*/
47+
public class MappingDescriptionVisitor implements RouterFunctions.Visitor, RequestPredicates.Visitor {
48+
49+
private final Deque<StringBuilder> predicateStack = new ArrayDeque<>();
50+
51+
private final List<DispatcherHandlerMappingDescription> descriptions = new ArrayList<>();
52+
53+
private final Stack<List<DispatcherHandlerMappingDescription>> nestedDescriptions = new Stack<>();
54+
55+
public List<DispatcherHandlerMappingDescription> getDescriptions() {
56+
return this.descriptions;
57+
}
58+
59+
// RouterFunctions.Visitor
60+
@Override
61+
public void startNested(RequestPredicate predicate) {
62+
this.predicateStack.push(new StringBuilder());
63+
this.nestedDescriptions.push(new ArrayList<>());
64+
predicate.accept(this);
65+
}
66+
67+
@Override
68+
public void endNested(RequestPredicate predicate) {
69+
String predicateInfo = this.predicateStack.pop().toString();
70+
List<DispatcherHandlerMappingDescription> nested = this.nestedDescriptions.pop();
71+
DispatcherHandlerMappingDescription description = new DispatcherHandlerMappingDescription(predicateInfo, null, null, nested);
72+
saveDescription(description);
73+
}
74+
75+
private void saveDescription(DispatcherHandlerMappingDescription description) {
76+
if (!this.nestedDescriptions.isEmpty()) {
77+
this.nestedDescriptions.peek().add(description);
78+
}
79+
else {
80+
this.descriptions.add(description);
81+
}
82+
}
83+
84+
@Override
85+
public void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction) {
86+
this.predicateStack.push(new StringBuilder());
87+
predicate.accept(this);
88+
String predicateInfo = this.predicateStack.pop().toString();
89+
DispatcherHandlerMappingDetails details = new DispatcherHandlerMappingDetails();
90+
details.setHandlerFunction(new HandlerFunctionDescription(handlerFunction));
91+
DispatcherHandlerMappingDescription description = new DispatcherHandlerMappingDescription(predicateInfo, handlerFunction.toString(), details);
92+
saveDescription(description);
93+
}
94+
95+
@Override
96+
public void resources(Function<ServerRequest, Mono<Resource>> lookupFunction) {
97+
saveDescription(new DispatcherHandlerMappingDescription(null, lookupFunction.toString(), null));
98+
}
99+
100+
101+
@Override
102+
public void attributes(Map<String, Object> attributes) {
103+
// No action needed for attributes
104+
}
105+
106+
@Override
107+
public void unknown(RouterFunction<?> routerFunction) {
108+
saveDescription(new DispatcherHandlerMappingDescription(null, routerFunction.toString(), null));
109+
}
110+
111+
// RequestPredicates.Visitor
112+
@Override
113+
public void method(Set<HttpMethod> methods) {
114+
if (methods.size() == 1) {
115+
append(methods.iterator().next());
116+
}
117+
else {
118+
append(methods);
119+
}
120+
}
121+
122+
private void append(Object value) {
123+
StringBuilder current = this.predicateStack.peek();
124+
if (current != null) {
125+
current.append(value);
126+
}
127+
}
128+
129+
@Override
130+
public void path(String pattern) {
131+
append(pattern);
132+
}
133+
134+
@Override
135+
public void pathExtension(String extension) {
136+
append(String.format("*.%s", extension));
137+
}
138+
139+
@Override
140+
public void header(String name, String value) {
141+
append(String.format("%s: %s", name, value));
142+
}
143+
144+
@Override
145+
public void queryParam(String name, String value) {
146+
append(String.format("?%s == %s", name, value));
147+
}
148+
149+
@Override
150+
public void startAnd() {
151+
append('(');
152+
}
153+
154+
@Override
155+
public void and() {
156+
append(" && ");
157+
}
158+
159+
@Override
160+
public void endAnd() {
161+
append(')');
162+
}
163+
164+
@Override
165+
public void startOr() {
166+
append('(');
167+
}
168+
169+
@Override
170+
public void or() {
171+
append(" || ");
172+
}
173+
174+
@Override
175+
public void endOr() {
176+
append(')');
177+
}
178+
179+
@Override
180+
public void startNegate() {
181+
append("!(");
182+
}
183+
184+
@Override
185+
public void endNegate() {
186+
append(')');
187+
}
188+
189+
@Override
190+
public void unknown(RequestPredicate predicate) {
191+
append(predicate);
192+
}
193+
194+
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletMappingDescription.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.boot.actuate.web.mappings.servlet;
1818

19+
import java.util.List;
20+
1921
import org.springframework.web.servlet.DispatcherServlet;
2022

2123
/**
@@ -30,12 +32,22 @@ public class DispatcherServletMappingDescription {
3032

3133
private final String predicate;
3234

35+
private final List<DispatcherServletMappingDescription> children;
36+
3337
private final DispatcherServletMappingDetails details;
3438

39+
public DispatcherServletMappingDescription(String predicate, String handler, DispatcherServletMappingDetails details, List<DispatcherServletMappingDescription> children) {
40+
this.handler = handler;
41+
this.predicate = predicate;
42+
this.details = details;
43+
this.children = children;
44+
}
45+
3546
DispatcherServletMappingDescription(String predicate, String handler, DispatcherServletMappingDetails details) {
3647
this.handler = handler;
3748
this.predicate = predicate;
3849
this.details = details;
50+
this.children = null;
3951
}
4052

4153
public String getHandler() {
@@ -46,6 +58,10 @@ public String getPredicate() {
4658
return this.predicate;
4759
}
4860

61+
public List<DispatcherServletMappingDescription> getChildren() {
62+
return this.children;
63+
}
64+
4965
public DispatcherServletMappingDetails getDetails() {
5066
return this.details;
5167
}

0 commit comments

Comments
 (0)