diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/jersey/JerseyEndpointResourceFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/jersey/JerseyEndpointResourceFactory.java index cf27addf3a1..4f9bb5d2537 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/jersey/JerseyEndpointResourceFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/jersey/JerseyEndpointResourceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -55,6 +55,7 @@ import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate; import org.springframework.boot.actuate.endpoint.web.WebServerNamespace; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.util.AntPathMatcher; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -189,8 +190,10 @@ public class JerseyEndpointResourceFactory { } @SuppressWarnings("unchecked") - private Map extractBodyArguments(ContainerRequestContext data) { - Map entity = ((ContainerRequest) data).readEntity(Map.class); + private Map extractBodyArguments(ContainerRequestContext data) { + Map entity = ((ContainerRequest) data).readEntity(Map.class, + new ParameterizedTypeReference>() { + }.getType()); return (entity != null) ? entity : Collections.emptyMap(); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java index cc2286270fd..dbdf5569ca4 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java @@ -314,6 +314,24 @@ public abstract class AbstractWebEndpointIntegrationTests { + Map body = new HashMap<>(); + body.put("generic", List.of("one", "two")); + client.post().uri("/test/one").bodyValue(body).exchange().expectStatus().isBadRequest(); + }); + } + + @Test + void writeOperationWithNestedValueIsRejected() { + load(TestEndpointConfiguration.class, (client) -> { + Map body = new HashMap<>(); + body.put("generic", Map.of("nested", "one")); + client.post().uri("/test/one").bodyValue(body).exchange().expectStatus().isBadRequest(); + }); + } + @Test void writeOperationWithVoidResponse() { load(VoidWriteResponseEndpointConfiguration.class, (context, client) -> { @@ -968,6 +986,11 @@ public abstract class AbstractWebEndpointIntegrationTests deletePart(@Selector String part) { return Collections.singletonMap("part", part);