diff --git a/module/spring-boot-actuator/build.gradle b/module/spring-boot-actuator/build.gradle index ffe57cce27d..88e14b7e91f 100644 --- a/module/spring-boot-actuator/build.gradle +++ b/module/spring-boot-actuator/build.gradle @@ -30,7 +30,6 @@ dependencies { optional(project(":module:spring-boot-health")) optional(project(":module:spring-boot-http-converter")) optional(project(":module:spring-boot-jsonb")) - optional(project(":module:spring-boot-validation")) optional("com.github.ben-manes.caffeine:caffeine") optional("com.google.code.findbugs:jsr305") optional("com.zaxxer:HikariCP") diff --git a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java index dcdec9d7130..08d8df4bcd6 100644 --- a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java +++ b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java @@ -21,23 +21,30 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import jakarta.validation.Validator; import org.junit.jupiter.api.Test; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; -import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; -import org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Role; +import org.springframework.util.ClassUtils; import org.springframework.validation.annotation.Validated; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; @@ -68,14 +75,14 @@ class ControllerEndpointDiscovererTests { ExposableControllerEndpoint endpoint = endpoints.iterator().next(); assertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of("testcontroller")); assertThat(endpoint.getController()).isInstanceOf(TestControllerEndpoint.class); + assertThat(ClassUtils.isCglibProxy(endpoint.getController())).isFalse(); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); })); } @Test void getEndpointsShouldDiscoverProxyControllerEndpoints() { - this.contextRunner.withUserConfiguration(TestProxyControllerEndpoint.class) - .withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class)) + this.contextRunner.withUserConfiguration(ProxyBeanConfiguration.class, TestProxyControllerEndpoint.class) .run(assertDiscoverer((discoverer) -> { Collection endpoints = discoverer.getEndpoints(); assertThat(endpoints).hasSize(1); @@ -83,6 +90,7 @@ class ControllerEndpointDiscovererTests { assertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of("testcontroller")); assertThat(endpoint.getController()).isInstanceOf(TestProxyControllerEndpoint.class); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); + assertThat(ClassUtils.isCglibProxy(endpoint.getController())).isTrue(); })); } @@ -95,19 +103,20 @@ class ControllerEndpointDiscovererTests { ExposableControllerEndpoint endpoint = endpoints.iterator().next(); assertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of("testrestcontroller")); assertThat(endpoint.getController()).isInstanceOf(TestRestControllerEndpoint.class); + assertThat(ClassUtils.isCglibProxy(endpoint.getController())).isFalse(); })); } @Test void getEndpointsShouldDiscoverProxyRestControllerEndpoints() { - this.contextRunner.withUserConfiguration(TestProxyRestControllerEndpoint.class) - .withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class)) + this.contextRunner.withUserConfiguration(ProxyBeanConfiguration.class, TestProxyRestControllerEndpoint.class) .run(assertDiscoverer((discoverer) -> { Collection endpoints = discoverer.getEndpoints(); assertThat(endpoints).hasSize(1); ExposableControllerEndpoint endpoint = endpoints.iterator().next(); assertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of("testrestcontroller")); assertThat(endpoint.getController()).isInstanceOf(TestProxyRestControllerEndpoint.class); + assertThat(ClassUtils.isCglibProxy(endpoint.getController())).isTrue(); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); })); } @@ -197,4 +206,22 @@ class ControllerEndpointDiscovererTests { } + static class ProxyBeanConfiguration { + + @Bean + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext) { + return new LocalValidatorFactoryBean(); + } + + @Bean + static MethodValidationPostProcessor methodValidationPostProcessor(ObjectProvider validator) { + MethodValidationPostProcessor processor = new MethodValidationPostProcessor(); + processor.setProxyTargetClass(true); + processor.setValidatorProvider(validator); + return processor; + } + + } + } diff --git a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java index cb26678bd7d..312ad109bcd 100644 --- a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java +++ b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java @@ -27,9 +27,12 @@ import jakarta.servlet.GenericServlet; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; +import jakarta.validation.ValidatorFactory; +import org.assertj.core.extractor.Extractors; import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; +import org.springframework.aop.framework.ProxyFactory; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; @@ -39,14 +42,15 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.web.EndpointServlet; import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint; -import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; -import org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.util.ClassUtils; import org.springframework.validation.annotation.Validated; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.validation.beanvalidation.MethodValidationInterceptor; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; @@ -77,22 +81,24 @@ class ServletEndpointDiscovererTests { ExposableServletEndpoint endpoint = endpoints.iterator().next(); assertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of("testservlet")); assertThat(endpoint.getEndpointServlet()).isNotNull(); + Object servlet = Extractors.byName("servlet").apply(endpoint.getEndpointServlet()); + assertThat(ClassUtils.isCglibProxy(servlet)).isFalse(); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); })); } @Test void getEndpointsShouldDiscoverProxyServletEndpoints() { - this.contextRunner.withUserConfiguration(TestProxyServletEndpoint.class) - .withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class)) - .run(assertDiscoverer((discoverer) -> { - Collection endpoints = discoverer.getEndpoints(); - assertThat(endpoints).hasSize(1); - ExposableServletEndpoint endpoint = endpoints.iterator().next(); - assertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of("testservlet")); - assertThat(endpoint.getEndpointServlet()).isNotNull(); - assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); - })); + this.contextRunner.withUserConfiguration(TestProxyServletEndpoint.class).run(assertDiscoverer((discoverer) -> { + Collection endpoints = discoverer.getEndpoints(); + assertThat(endpoints).hasSize(1); + ExposableServletEndpoint endpoint = endpoints.iterator().next(); + assertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of("testservlet")); + assertThat(endpoint.getEndpointServlet()).isNotNull(); + Object servlet = Extractors.byName("servlet").apply(endpoint.getEndpointServlet()); + assertThat(ClassUtils.isCglibProxy(servlet)).isTrue(); + assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); + })); } @Test @@ -179,7 +185,17 @@ class ServletEndpointDiscovererTests { @Override public EndpointServlet get() { - return new EndpointServlet(TestServlet.class); + ValidatorFactory validator = new LocalValidatorFactoryBean(); + TestServlet target = new TestServlet(); + MethodValidationInterceptor interceptor = new MethodValidationInterceptor(validator); + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTargetClass(EndpointServlet.class); + proxyFactory.setTarget(target); + proxyFactory.setProxyTargetClass(true); + proxyFactory.addAdvice(interceptor); + proxyFactory.getProxy(); + TestServlet servlet = (TestServlet) proxyFactory.getProxy(); + return new EndpointServlet(servlet); } }