Skip to content

Commit 89354f3

Browse files
Merge branch '3.1.x' into 3.2.x
Closes gh-39444
2 parents 5ae533a + 2374e7d commit 89354f3

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMapping.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
* @author Madhura Bhave
8484
* @author Phillip Webb
8585
* @author Brian Clozel
86+
* @author Scott Frederick
8687
* @since 2.0.0
8788
*/
8889
@ImportRuntimeHints(AbstractWebFluxEndpointHandlerMappingRuntimeHints.class)
@@ -260,6 +261,26 @@ public Object invoke(InvocationContext context) {
260261

261262
}
262263

264+
protected static final class ExceptionCapturingInvoker implements OperationInvoker {
265+
266+
private final OperationInvoker invoker;
267+
268+
public ExceptionCapturingInvoker(OperationInvoker invoker) {
269+
this.invoker = invoker;
270+
}
271+
272+
@Override
273+
public Object invoke(InvocationContext context) {
274+
try {
275+
return this.invoker.invoke(context);
276+
}
277+
catch (Exception ex) {
278+
return Mono.error(ex);
279+
}
280+
}
281+
282+
}
283+
263284
/**
264285
* Reactive handler providing actuator links at the root endpoint.
265286
*/
@@ -303,9 +324,9 @@ private ReactiveWebOperationAdapter(WebOperation operation) {
303324
private OperationInvoker getInvoker(WebOperation operation) {
304325
OperationInvoker invoker = operation::invoke;
305326
if (operation.isBlocking()) {
306-
invoker = new ElasticSchedulerInvoker(invoker);
327+
return new ElasticSchedulerInvoker(invoker);
307328
}
308-
return invoker;
329+
return new ExceptionCapturingInvoker(invoker);
309330
}
310331

311332
private Supplier<Mono<? extends SecurityContext>> getSecurityContextSupplier() {

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java

+46
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,31 @@ void readOperationWithSingleQueryParameters() {
226226
.isEqualTo("1 2"));
227227
}
228228

229+
@Test
230+
void readOperationWithQueryParametersMissing() {
231+
load(QueryEndpointConfiguration.class,
232+
(client) -> client.get().uri("/query").exchange().expectStatus().isBadRequest());
233+
}
234+
235+
@Test
236+
void reactiveReadOperationWithSingleQueryParameters() {
237+
load(ReactiveQueryEndpointConfiguration.class,
238+
(client) -> client.get()
239+
.uri("/query?param=test")
240+
.exchange()
241+
.expectStatus()
242+
.isOk()
243+
.expectBody()
244+
.jsonPath("query")
245+
.isEqualTo("test"));
246+
}
247+
248+
@Test
249+
void reactiveReadOperationWithQueryParametersMissing() {
250+
load(ReactiveQueryEndpointConfiguration.class,
251+
(client) -> client.get().uri("/query").exchange().expectStatus().isBadRequest());
252+
}
253+
229254
@Test
230255
void readOperationWithSingleQueryParametersAndMultipleValues() {
231256
load(QueryEndpointConfiguration.class,
@@ -732,6 +757,17 @@ QueryWithListEndpoint queryEndpoint() {
732757

733758
}
734759

760+
@Configuration(proxyBeanMethods = false)
761+
@Import(BaseConfiguration.class)
762+
static class ReactiveQueryEndpointConfiguration {
763+
764+
@Bean
765+
ReactiveQueryEndpoint reactiveQueryEndpoint() {
766+
return new ReactiveQueryEndpoint();
767+
}
768+
769+
}
770+
735771
@Configuration(proxyBeanMethods = false)
736772
@Import(BaseConfiguration.class)
737773
static class VoidWriteResponseEndpointConfiguration {
@@ -974,6 +1010,16 @@ Map<String, String> queryWithParameterList(String one, List<String> two) {
9741010

9751011
}
9761012

1013+
@Endpoint(id = "query")
1014+
static class ReactiveQueryEndpoint {
1015+
1016+
@ReadOperation
1017+
Mono<Map<String, String>> query(String param) {
1018+
return Mono.just(Collections.singletonMap("query", param));
1019+
}
1020+
1021+
}
1022+
9771023
@Endpoint(id = "voidwrite")
9781024
static class VoidWriteResponseEndpoint {
9791025

0 commit comments

Comments
 (0)