From 584b7d134324fecb68d89b81306261e52ce5f108 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Mon, 18 Jul 2022 15:45:07 +0200 Subject: [PATCH] Add AOT support for actuator Mainly adds reflection hints for the actuator infrastructure. Also adds the OperationReflectiveProcessor, which registers the @ReadMethod, @DeleteMethod and @WriteMethod annotated methods for reflection and adds reflection hints for method return types. See gh-31671 --- .../CloudFoundryWebEndpointDiscoverer.java | 18 ++- ...dFoundryWebFluxEndpointHandlerMapping.java | 26 +++- ...undryWebEndpointServletHandlerMapping.java | 25 ++++ .../endpoint/EndpointAutoConfiguration.java | 3 + .../ThreadDumpEndpointAutoConfiguration.java | 11 ++ ...ebEndpointDiscovererRuntimeHintsTests.java | 45 ++++++ ...dpointHandlerMappingRuntimeHintsTests.java | 46 ++++++ ...ervletHandlerMappingRuntimeHintsTests.java | 47 +++++++ ...eadDumpEndpointAutoConfigurationTests.java | 21 ++- ...uatorAnnotationsRuntimeHintsRegistrar.java | 49 +++++++ .../boot/actuate/aot/package-info.java | 20 +++ .../endpoint/annotation/DeleteOperation.java | 4 +- .../actuate/endpoint/annotation/Endpoint.java | 4 +- .../annotation/EndpointExtension.java | 4 +- .../OperationReflectiveProcessor.java | 74 ++++++++++ .../endpoint/annotation/ReadOperation.java | 4 +- .../endpoint/annotation/WriteOperation.java | 4 +- .../jmx/annotation/JmxEndpointDiscoverer.java | 18 ++- .../ControllerEndpointDiscoverer.java | 18 ++- .../annotation/ServletEndpointDiscoverer.java | 18 ++- .../web/annotation/WebEndpointDiscoverer.java | 18 ++- ...AbstractWebFluxEndpointHandlerMapping.java | 23 +++ .../WebFluxEndpointHandlerMapping.java | 26 +++- .../AbstractWebMvcEndpointHandlerMapping.java | 19 +++ .../servlet/WebMvcEndpointHandlerMapping.java | 27 +++- .../health/HealthEndpointWebExtension.java | 18 +++ .../actuate/info/BuildInfoContributor.java | 19 ++- .../boot/actuate/info/GitInfoContributor.java | 19 ++- .../actuate/info/JavaInfoContributor.java | 19 ++- .../boot/actuate/info/OsInfoContributor.java | 17 +++ .../integration/IntegrationGraphEndpoint.java | 40 +++++- .../management/ThreadDumpEndpoint.java | 39 +++++- .../ThreadDumpEndpointWebExtension.java | 60 ++++++++ .../HazelcastCacheMeterBinderProvider.java | 22 +++ .../quartz/QuartzEndpointWebExtension.java | 23 ++- .../scheduling/ScheduledTasksEndpoint.java | 18 +++ .../boot/actuate/startup/StartupEndpoint.java | 31 +++- ...herHandlersMappingDescriptionProvider.java | 20 ++- ...herServletsMappingDescriptionProvider.java | 18 +++ .../FiltersMappingDescriptionProvider.java | 18 +++ .../ServletsMappingDescriptionProvider.java | 18 +++ ...AnnotationsRuntimeHintsRegistrarTests.java | 73 ++++++++++ .../OperationReflectiveProcessorTests.java | 132 ++++++++++++++++++ ...mxEndpointDiscovererRuntimeHintsTests.java | 45 ++++++ ...erEndpointDiscovererRuntimeHintsTests.java | 46 ++++++ ...etEndpointDiscovererRuntimeHintsTests.java | 46 ++++++ ...ebEndpointDiscovererRuntimeHintsTests.java | 46 ++++++ ...dpointHandlerMappingRuntimeHintsTests.java | 49 +++++++ ...dpointHandlerMappingRuntimeHintsTests.java | 47 +++++++ ...dpointHandlerMappingRuntimeHintsTests.java | 46 ++++++ ...dpointHandlerMappingRuntimeHintsTests.java | 47 +++++++ ...EndpointWebExtensionRuntimeHintsTests.java | 51 +++++++ ...BuildInfoContributorRuntimeHintsTests.java | 47 +++++++ .../GitInfoContributorRuntimeHintsTests.java | 48 +++++++ .../JavaInfoContributorRuntimeHintsTests.java | 47 +++++++ .../OsInfoContributorRuntimeHintsTests.java | 48 +++++++ ...grationGraphEndpointRuntimeHintsTests.java | 72 ++++++++++ .../ThreadDumpEndpointWebExtensionTests.java | 63 +++++++++ ...eMeterBinderProviderRuntimeHintsTests.java | 47 +++++++ ...EndpointWebExtensionRuntimeHintsTests.java | 56 ++++++++ ...heduledTasksEndpointRuntimeHintsTests.java | 56 ++++++++ .../StartupEndpointRuntimeHintsTests.java | 53 +++++++ ...gDescriptionProviderRuntimeHintsTests.java | 47 +++++++ ...gDescriptionProviderRuntimeHintsTests.java | 46 ++++++ ...gDescriptionProviderRuntimeHintsTests.java | 47 +++++++ ...gDescriptionProviderRuntimeHintsTests.java | 46 ++++++ .../boot/info/BuildProperties.java | 17 ++- .../boot/info/GitProperties.java | 17 ++- .../BuildPropertiesRuntimeHintsTests.java | 44 ++++++ .../info/GitPropertiesRuntimeHintsTests.java | 43 ++++++ 70 files changed, 2413 insertions(+), 30 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMappingRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMappingRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrar.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessor.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtension.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrarTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessorTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMappingRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMappingRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMappingRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMappingRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/BuildInfoContributorRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/GitInfoContributorRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/JavaInfoContributorRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtensionTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProviderRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtensionRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpointRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/startup/StartupEndpointRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProviderRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProviderRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProviderRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProviderRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/BuildPropertiesRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesRuntimeHintsTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscoverer.java index a01fe72a924..ccce3906243 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -19,6 +19,10 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry; import java.util.Collection; import java.util.List; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints; import org.springframework.boot.actuate.endpoint.EndpointFilter; import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor; import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; @@ -29,6 +33,7 @@ import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExten import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.core.annotation.MergedAnnotations; /** @@ -38,6 +43,7 @@ import org.springframework.core.annotation.MergedAnnotations; * @author Madhura Bhave * @since 2.0.0 */ +@ImportRuntimeHints(CloudFoundryWebEndpointDiscovererRuntimeHints.class) public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer { /** @@ -75,4 +81,14 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer { return MergedAnnotations.from(extensionBeanType).isPresent(EndpointCloudFoundryExtension.class); } + static class CloudFoundryWebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(CloudFoundryEndpointFilter.class, + (hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java index 0df6400d0a0..dbca38daa42 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -19,14 +19,20 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse; +import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; @@ -35,6 +41,8 @@ import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.Link; import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -50,6 +58,7 @@ import org.springframework.web.server.ServerWebExchange; * @author Phillip Webb * @author Brian Clozel */ +@ImportRuntimeHints(CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints.class) class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping { private final CloudFoundrySecurityInterceptor securityInterceptor; @@ -145,4 +154,19 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH } + static class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(CloudFoundryLinksHandler.class, + (hint) -> hint.onReachableType(TypeReference.of(CloudFoundryLinksHandler.class)).withMethod("links", + List.of(TypeReference.of(ServerWebExchange.class)), + (method) -> method.setModes(ExecutableMode.INVOKE))); + this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java index fd8fe0e74cb..5ccac0b0455 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -27,8 +28,13 @@ import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse; +import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; @@ -37,6 +43,8 @@ import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.Link; import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ResponseBody; @@ -51,6 +59,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi * @author Phillip Webb * @author Brian Clozel */ +@ImportRuntimeHints(CloudFoundryWebEndpointServletHandlerMappingRuntimeHints.class) class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpointHandlerMapping { private static final Log logger = LogFactory.getLog(CloudFoundryWebEndpointServletHandlerMapping.class); @@ -147,4 +156,20 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin } + static class CloudFoundryWebEndpointServletHandlerMappingRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(CloudFoundryLinksHandler.class, + (hint) -> hint.onReachableType(TypeReference.of(CloudFoundryLinksHandler.class)).withMethod("links", + List.of(TypeReference.of(HttpServletRequest.class), + TypeReference.of(HttpServletResponse.class)), + (method) -> method.setModes(ExecutableMode.INVOKE))); + this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java index a7bcd2f262e..01951ce41fa 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.actuate.aot.ActuatorAnnotationsRuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.EndpointConverter; import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; @@ -30,6 +31,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter; @@ -45,6 +47,7 @@ import org.springframework.core.env.Environment; * @since 2.0.0 */ @AutoConfiguration +@ImportRuntimeHints(ActuatorAnnotationsRuntimeHintsRegistrar.class) public class EndpointAutoConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfiguration.java index d5e00f03e58..939e74de191 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfiguration.java @@ -17,9 +17,12 @@ package org.springframework.boot.actuate.autoconfigure.management; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; +import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure; import org.springframework.boot.actuate.management.ThreadDumpEndpoint; +import org.springframework.boot.actuate.management.ThreadDumpEndpointWebExtension; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -39,4 +42,12 @@ public class ThreadDumpEndpointAutoConfiguration { return new ThreadDumpEndpoint(); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(ThreadDumpEndpoint.class) + @ConditionalOnAvailableEndpoint(exposure = { EndpointExposure.WEB, EndpointExposure.CLOUD_FOUNDRY }) + public ThreadDumpEndpointWebExtension threadDumpWebExtension(ThreadDumpEndpoint threadDumpEndpoint) { + return new ThreadDumpEndpointWebExtension(threadDumpEndpoint); + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererRuntimeHintsTests.java new file mode 100644 index 00000000000..7aea479685b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererRuntimeHintsTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.cloudfoundry; + +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.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CloudFoundryWebEndpointDiscovererRuntimeHints}. + * + * @author Moritz Halbritter + */ +class CloudFoundryWebEndpointDiscovererRuntimeHintsTests { + + private final CloudFoundryWebEndpointDiscovererRuntimeHints sut = new CloudFoundryWebEndpointDiscovererRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(CloudFoundryEndpointFilter.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMappingRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMappingRuntimeHintsTests.java new file mode 100644 index 00000000000..f4043f317d6 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMappingRuntimeHintsTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryLinksHandler; +import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints; +import org.springframework.boot.actuate.endpoint.web.Link; + +/** + * Tests for {@link CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints}. + * + * @author Moritz Halbritter + */ +class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHintsTests { + + private final CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints sut = new CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + Assertions.assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links")) + .accepts(runtimeHints); + Assertions.assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMappingRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMappingRuntimeHintsTests.java new file mode 100644 index 00000000000..03902421ee8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMappingRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryLinksHandler; +import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints; +import org.springframework.boot.actuate.endpoint.web.Link; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CloudFoundryWebEndpointServletHandlerMappingRuntimeHints}. + * + * @author Moritz Halbritter + */ +class CloudFoundryWebEndpointServletHandlerMappingRuntimeHintsTests { + + private final CloudFoundryWebEndpointServletHandlerMappingRuntimeHints sut = new CloudFoundryWebEndpointServletHandlerMappingRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links")) + .accepts(runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfigurationTests.java index ac7fb7be205..5d8d895a6b8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.management; import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.management.ThreadDumpEndpoint; +import org.springframework.boot.actuate.management.ThreadDumpEndpointWebExtension; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -28,6 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link ThreadDumpEndpointAutoConfiguration}. * * @author Phillip Webb + * @author Moritz Halbritter */ class ThreadDumpEndpointAutoConfigurationTests { @@ -36,20 +38,27 @@ class ThreadDumpEndpointAutoConfigurationTests { @Test void runShouldHaveEndpointBean() { - this.contextRunner.withPropertyValues("management.endpoints.web.exposure.include=threaddump") - .run((context) -> assertThat(context).hasSingleBean(ThreadDumpEndpoint.class)); + this.contextRunner.withPropertyValues("management.endpoints.web.exposure.include=threaddump").run((context) -> { + assertThat(context).hasSingleBean(ThreadDumpEndpoint.class); + assertThat(context).hasSingleBean(ThreadDumpEndpointWebExtension.class); + }); } @Test void runWhenNotExposedShouldNotHaveEndpointBean() { - this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ThreadDumpEndpoint.class)); + this.contextRunner.run((context) -> { + assertThat(context).doesNotHaveBean(ThreadDumpEndpoint.class); + assertThat(context).doesNotHaveBean(ThreadDumpEndpointWebExtension.class); + }); } @Test void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() { this.contextRunner.withPropertyValues("management.endpoints.web.exposure.include=*") - .withPropertyValues("management.endpoint.threaddump.enabled:false") - .run((context) -> assertThat(context).doesNotHaveBean(ThreadDumpEndpoint.class)); + .withPropertyValues("management.endpoint.threaddump.enabled:false").run((context) -> { + assertThat(context).doesNotHaveBean(ThreadDumpEndpoint.class); + assertThat(context).doesNotHaveBean(ThreadDumpEndpointWebExtension.class); + }); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrar.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrar.java new file mode 100644 index 00000000000..87a6fc6eece --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrar.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.aot; + +import java.util.stream.Stream; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.support.RuntimeHintsUtils; +import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; +import org.springframework.core.annotation.SynthesizedAnnotation; + +/** + * Registrar which registers the annotations needed for actuator support. + * + * @author Moritz Halbritter + * @since 3.0.0 + */ +public class ActuatorAnnotationsRuntimeHintsRegistrar implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + Stream.of(Endpoint.class, ReadOperation.class, WriteOperation.class, DeleteOperation.class, + EndpointExtension.class) + .forEach((annotationType) -> RuntimeHintsUtils.registerAnnotation(hints, annotationType)); + // TODO: See https://github.com/spring-projects/spring-framework/issues/28767 + Stream.of(Endpoint.class, EndpointExtension.class).forEach( + (annotationType) -> hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/package-info.java new file mode 100644 index 00000000000..15e4e2bd037 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/aot/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Support classes for actuator in AOT mode. + */ +package org.springframework.boot.actuate.aot; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DeleteOperation.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DeleteOperation.java index a0525045890..3b9df3d745a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DeleteOperation.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DeleteOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -22,6 +22,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.aot.hint.annotation.Reflective; import org.springframework.boot.actuate.endpoint.Producible; /** @@ -34,6 +35,7 @@ import org.springframework.boot.actuate.endpoint.Producible; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented +@Reflective(OperationReflectiveProcessor.class) public @interface DeleteOperation { /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java index de1848073eb..8f8c793e422 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -22,6 +22,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.aot.hint.annotation.Reflective; import org.springframework.boot.actuate.endpoint.EndpointId; /** @@ -51,6 +52,7 @@ import org.springframework.boot.actuate.endpoint.EndpointId; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented +@Reflective public @interface Endpoint { /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointExtension.java index 94fb64d3d72..84564372f3a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -22,6 +22,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.aot.hint.annotation.Reflective; import org.springframework.boot.actuate.endpoint.EndpointFilter; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.core.annotation.AliasFor; @@ -51,6 +52,7 @@ import org.springframework.core.annotation.AliasFor; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented +@Reflective public @interface EndpointExtension { /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessor.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessor.java new file mode 100644 index 00000000000..55329c0748a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessor.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.annotation; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.ReflectionHints; +import org.springframework.aot.hint.annotation.ReflectiveProcessor; +import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; +import org.springframework.core.ResolvableType; +import org.springframework.core.io.Resource; + +/** + * Processor which registers the annotated operation method and its return type for + * reflection. + * + * @author Moritz Halbritter + */ +class OperationReflectiveProcessor implements ReflectiveProcessor { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { + if (!(element instanceof Method method)) { + throw new IllegalArgumentException("This processor can only be invoked for annotated methods"); + } + hints.registerMethod(method, (hint) -> hint.setModes(ExecutableMode.INVOKE)); + registerReturnValueHints(hints, method); + } + + private void registerReturnValueHints(ReflectionHints hints, Method method) { + ResolvableType returnType = ResolvableType.forMethodReturnType(method); + if (WebEndpointResponse.class.isAssignableFrom(method.getReturnType())) { + registerWebEndpointResponse(hints, returnType); + } + else { + registerReflectionHints(hints, returnType.getType()); + } + } + + private void registerWebEndpointResponse(ReflectionHints hints, ResolvableType returnType) { + ResolvableType genericParameter = returnType.getGeneric(0); + if (genericParameter.getRawClass() != null) { + registerReflectionHints(hints, genericParameter.getType()); + } + } + + private void registerReflectionHints(ReflectionHints hints, Type type) { + if (type.equals(Resource.class)) { + return; + } + this.bindingRegistrar.registerReflectionHints(hints, type); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/ReadOperation.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/ReadOperation.java index 1997393171c..ead39bc309a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/ReadOperation.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/ReadOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -22,6 +22,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.aot.hint.annotation.Reflective; import org.springframework.boot.actuate.endpoint.Producible; /** @@ -33,6 +34,7 @@ import org.springframework.boot.actuate.endpoint.Producible; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented +@Reflective(OperationReflectiveProcessor.class) public @interface ReadOperation { /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/WriteOperation.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/WriteOperation.java index df39b75fec3..b9a63c4f69e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/WriteOperation.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/WriteOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -22,6 +22,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.aot.hint.annotation.Reflective; import org.springframework.boot.actuate.endpoint.Producible; /** @@ -33,6 +34,7 @@ import org.springframework.boot.actuate.endpoint.Producible; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented +@Reflective(OperationReflectiveProcessor.class) public @interface WriteOperation { /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java index f9106e3fe1f..7dde444a5c3 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -18,6 +18,9 @@ package org.springframework.boot.actuate.endpoint.jmx.annotation; import java.util.Collection; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.EndpointFilter; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; @@ -28,7 +31,9 @@ import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint; import org.springframework.boot.actuate.endpoint.jmx.JmxEndpointsSupplier; import org.springframework.boot.actuate.endpoint.jmx.JmxOperation; +import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointDiscoverer.JmxEndpointDiscovererRuntimeHints; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; /** * {@link EndpointDiscoverer} for {@link ExposableJmxEndpoint JMX endpoints}. @@ -36,6 +41,7 @@ import org.springframework.context.ApplicationContext; * @author Phillip Webb * @since 2.0.0 */ +@ImportRuntimeHints(JmxEndpointDiscovererRuntimeHints.class) public class JmxEndpointDiscoverer extends EndpointDiscoverer implements JmxEndpointsSupplier { @@ -69,4 +75,14 @@ public class JmxEndpointDiscoverer extends EndpointDiscoverer "MBean call '" + operation.getName() + "'"); } + static class JmxEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(JmxEndpointFilter.class, + (hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java index 1b991c71ffa..43b61812070 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -20,6 +20,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.EndpointFilter; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.Operation; @@ -28,7 +31,9 @@ import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; import org.springframework.boot.actuate.endpoint.web.PathMapper; +import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer.ControllerEndpointDiscovererRuntimeHints; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; @@ -39,6 +44,7 @@ import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; * @author Phillip Webb * @since 2.0.0 */ +@ImportRuntimeHints(ControllerEndpointDiscovererRuntimeHints.class) public class ControllerEndpointDiscoverer extends EndpointDiscoverer implements ControllerEndpointsSupplier { @@ -80,4 +86,14 @@ public class ControllerEndpointDiscoverer extends EndpointDiscoverer hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java index 0349c4a3d19..366a55210a1 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -20,6 +20,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.EndpointFilter; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.Operation; @@ -29,7 +32,9 @@ import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint; import org.springframework.boot.actuate.endpoint.web.PathMapper; +import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer.ServletEndpointDiscovererRuntimeHints; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; @@ -39,6 +44,7 @@ import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; * @author Phillip Webb * @since 2.0.0 */ +@ImportRuntimeHints(ServletEndpointDiscovererRuntimeHints.class) public class ServletEndpointDiscoverer extends EndpointDiscoverer implements ServletEndpointsSupplier { @@ -79,4 +85,14 @@ public class ServletEndpointDiscoverer extends EndpointDiscoverer hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java index 42d4d631b49..3c3004e7623 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -19,6 +19,9 @@ package org.springframework.boot.actuate.endpoint.web.annotation; import java.util.Collection; import java.util.List; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.EndpointFilter; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; @@ -32,7 +35,9 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier; import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate; +import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer.WebEndpointDiscovererRuntimeHints; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; /** * {@link EndpointDiscoverer} for {@link ExposableWebEndpoint web endpoints}. @@ -40,6 +45,7 @@ import org.springframework.context.ApplicationContext; * @author Phillip Webb * @since 2.0.0 */ +@ImportRuntimeHints(WebEndpointDiscovererRuntimeHints.class) public class WebEndpointDiscoverer extends EndpointDiscoverer implements WebEndpointsSupplier { @@ -87,4 +93,14 @@ public class WebEndpointDiscoverer extends EndpointDiscoverer "web request predicate " + operation.getRequestPredicate()); } + static class WebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(WebEndpointFilter.class, + (hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMapping.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMapping.java index 1c0e1ab1807..0c0e38ce9ac 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMapping.java @@ -22,6 +22,7 @@ import java.security.Principal; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -30,6 +31,10 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException; import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.OperationArgumentResolver; @@ -44,7 +49,9 @@ 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.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints; import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -80,6 +87,7 @@ import org.springframework.web.util.pattern.PathPattern; * @author Brian Clozel * @since 2.0.0 */ +@ImportRuntimeHints(AbstractWebFluxEndpointHandlerMappingRuntimeHints.class) public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappingInfoHandlerMapping { private final EndpointMapping endpointMapping; @@ -484,4 +492,19 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi } + static class AbstractWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(WriteOperationHandler.class, + (hint) -> hint.withMethod("handle", + List.of(TypeReference.of(ServerWebExchange.class), TypeReference.of(Map.class)), + (method) -> method.withMode(ExecutableMode.INVOKE))); + hints.reflection().registerType(ReadOperationHandler.class, + (hint) -> hint.withMethod("handle", List.of(TypeReference.of(ServerWebExchange.class)), + (method) -> method.withMode(ExecutableMode.INVOKE))); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMapping.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMapping.java index 2b0a7ae83f0..c18cc203d25 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -18,14 +18,22 @@ package org.springframework.boot.actuate.endpoint.web.reactive; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.Link; +import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.reactive.HandlerMapping; @@ -41,6 +49,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @author Brian Clozel * @since 2.0.0 */ +@ImportRuntimeHints(WebFluxEndpointHandlerMappingRuntimeHints.class) public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping implements InitializingBean { private final EndpointLinksResolver linksResolver; @@ -89,4 +98,19 @@ public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandle } + static class WebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(WebFluxLinksHandler.class, + (hint) -> hint.onReachableType(TypeReference.of(WebFluxLinksHandler.class)).withMethod("links", + List.of(TypeReference.of(ServerWebExchange.class)), + (method) -> method.setModes(ExecutableMode.INVOKE))); + this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMapping.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMapping.java index 3bc469d87c7..434ceca0299 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMapping.java @@ -32,6 +32,10 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import reactor.core.publisher.Flux; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException; import org.springframework.boot.actuate.endpoint.InvocationContext; @@ -46,7 +50,9 @@ 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.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints; import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -80,6 +86,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi * @author Brian Clozel * @since 2.0.0 */ +@ImportRuntimeHints(AbstractWebMvcEndpointHandlerMappingRuntimeHints.class) public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappingInfoHandlerMapping implements InitializingBean { @@ -476,4 +483,16 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin } + static class AbstractWebMvcEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(OperationHandler.class, + (hint) -> hint.withMethod("handle", + List.of(TypeReference.of(HttpServletRequest.class), TypeReference.of(Map.class)), + (method) -> method.withMode(ExecutableMode.INVOKE))); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMapping.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMapping.java index a6f3cfb96d4..3f853341512 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -18,16 +18,24 @@ package org.springframework.boot.actuate.endpoint.web.servlet; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.Link; +import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.servlet.HandlerMapping; @@ -40,6 +48,7 @@ import org.springframework.web.servlet.HandlerMapping; * @author Phillip Webb * @since 2.0.0 */ +@ImportRuntimeHints(WebMvcEndpointHandlerMappingRuntimeHints.class) public class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerMapping { private final EndpointLinksResolver linksResolver; @@ -86,4 +95,20 @@ public class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerM } + static class WebMvcEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(WebMvcLinksHandler.class, + (hint) -> hint.onReachableType(TypeReference.of(WebMvcLinksHandler.class)).withMethod("links", + List.of(TypeReference.of(HttpServletRequest.class), + TypeReference.of(HttpServletResponse.class)), + (method) -> method.setModes(ExecutableMode.INVOKE))); + this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java index e019e3e9bf5..13f940a5e1a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java @@ -21,6 +21,8 @@ import java.util.Arrays; import java.util.Map; import java.util.Set; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.ApiVersion; import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; @@ -29,6 +31,9 @@ import org.springframework.boot.actuate.endpoint.annotation.Selector.Match; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebServerNamespace; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; +import org.springframework.boot.actuate.health.HealthEndpointWebExtension.HealthEndpointWebExtensionRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; /** * {@link EndpointWebExtension @EndpointWebExtension} for the {@link HealthEndpoint}. @@ -44,6 +49,7 @@ import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExten * @since 2.0.0 */ @EndpointWebExtension(endpoint = HealthEndpoint.class) +@ImportRuntimeHints(HealthEndpointWebExtensionRuntimeHints.class) public class HealthEndpointWebExtension extends HealthEndpointSupport { private static final String[] NO_PATH = {}; @@ -110,4 +116,16 @@ public class HealthEndpointWebExtension extends HealthEndpointSupport { public BuildInfoContributor(BuildProperties properties) { @@ -56,4 +62,15 @@ public class BuildInfoContributor extends InfoPropertiesInfoContributor { public GitInfoContributor(GitProperties properties) { @@ -68,4 +74,15 @@ public class GitInfoContributor extends InfoPropertiesInfoContributor T getFormattedThreadDump(Function formatter) { - return formatter.apply(ManagementFactory.getThreadMXBean().dumpAllThreads(true, true)); + ThreadDumper threadDumper = createThreadDumper(); + return formatter.apply(threadDumper.dumpAllThreads()); + } + + private ThreadDumper createThreadDumper() { + if (NativeDetector.inNativeImage()) { + throw new ThreadDumperUnavailableException("Running in native image"); + } + return new ThreadMXBeanThreadDumper(); + } + + private interface ThreadDumper { + + ThreadInfo[] dumpAllThreads(); + + } + + private static class ThreadMXBeanThreadDumper implements ThreadDumper { + + @Override + public ThreadInfo[] dumpAllThreads() { + return ManagementFactory.getThreadMXBean().dumpAllThreads(true, true); + } + + } + + /** + * Exception to be thrown if the {@link ThreadDumper} cannot be created. + */ + static class ThreadDumperUnavailableException extends RuntimeException { + + ThreadDumperUnavailableException(String message) { + super(message); + } + } /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtension.java new file mode 100644 index 00000000000..76a1f38a301 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtension.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.management; + +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; +import org.springframework.boot.actuate.management.ThreadDumpEndpoint.ThreadDumpDescriptor; +import org.springframework.boot.actuate.management.ThreadDumpEndpoint.ThreadDumperUnavailableException; + +/** + * {@link EndpointWebExtension @EndpointWebExtension} for the {@link ThreadDumpEndpoint}. + * + * @author Moritz Halbritter + * @since 3.0.0 + */ +@EndpointWebExtension(endpoint = ThreadDumpEndpoint.class) +public class ThreadDumpEndpointWebExtension { + + private final ThreadDumpEndpoint delegate; + + public ThreadDumpEndpointWebExtension(ThreadDumpEndpoint delegate) { + this.delegate = delegate; + } + + @ReadOperation + public WebEndpointResponse threadDump() { + try { + return new WebEndpointResponse<>(this.delegate.threadDump()); + } + catch (ThreadDumperUnavailableException ex) { + return new WebEndpointResponse<>(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE); + } + } + + @ReadOperation(produces = "text/plain;charset=UTF-8") + public WebEndpointResponse textThreadDump() { + try { + return new WebEndpointResponse<>(this.delegate.textThreadDump()); + } + catch (ThreadDumperUnavailableException ex) { + return new WebEndpointResponse<>(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProvider.java index 92894ec0f45..a7f4f26de55 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProvider.java @@ -17,12 +17,19 @@ package org.springframework.boot.actuate.metrics.cache; import java.lang.reflect.Method; +import java.util.List; import com.hazelcast.spring.cache.HazelcastCache; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.binder.cache.HazelcastCacheMetrics; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; +import org.springframework.boot.actuate.metrics.cache.HazelcastCacheMeterBinderProvider.HazelcastCacheMeterBinderProviderRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.util.ReflectionUtils; /** @@ -31,6 +38,7 @@ import org.springframework.util.ReflectionUtils; * @author Stephane Nicoll * @since 2.0.0 */ +@ImportRuntimeHints(HazelcastCacheMeterBinderProviderRuntimeHints.class) public class HazelcastCacheMeterBinderProvider implements CacheMeterBinderProvider { @Override @@ -56,4 +64,18 @@ public class HazelcastCacheMeterBinderProvider implements CacheMeterBinderProvid } } + static class HazelcastCacheMeterBinderProviderRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType(HazelcastCache.class, (hint) -> hint.withMethod("getNativeCache", List.of(), + (method) -> method.withMode(ExecutableMode.INVOKE))); + hints.reflection().registerType(HazelcastCacheMetrics.class, + (hint) -> hint.withConstructor( + List.of(TypeReference.of(Object.class), TypeReference.of(Iterable.class)), + (ctor) -> ctor.withMode(ExecutableMode.INVOKE))); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtension.java index ab52b8707dd..e3468512e29 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -18,11 +18,19 @@ package org.springframework.boot.actuate.quartz; import org.quartz.SchedulerException; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzGroups; +import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzJobDetails; +import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzJobGroupSummary; +import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzTriggerGroupSummary; +import org.springframework.boot.actuate.quartz.QuartzEndpointWebExtension.QuartzEndpointWebExtensionRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; /** * {@link EndpointWebExtension @EndpointWebExtension} for the {@link QuartzEndpoint}. @@ -31,6 +39,7 @@ import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzGroups; * @since 2.5.0 */ @EndpointWebExtension(endpoint = QuartzEndpoint.class) +@ImportRuntimeHints(QuartzEndpointWebExtensionRuntimeHints.class) public class QuartzEndpointWebExtension { private final QuartzEndpoint delegate; @@ -84,4 +93,16 @@ public class QuartzEndpointWebExtension { } + static class QuartzEndpointWebExtensionRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + this.bindingRegistrar.registerReflectionHints(hints.reflection(), QuartzGroups.class, + QuartzJobDetails.class, QuartzJobGroupSummary.class, QuartzTriggerGroupSummary.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java index 18e87b16846..00f79598a5c 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java @@ -26,8 +26,13 @@ import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksEndpointRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.config.CronTask; import org.springframework.scheduling.config.FixedDelayTask; @@ -49,6 +54,7 @@ import org.springframework.scheduling.support.ScheduledMethodRunnable; * @since 2.0.0 */ @Endpoint(id = "scheduledtasks") +@ImportRuntimeHints(ScheduledTasksEndpointRuntimeHints.class) public class ScheduledTasksEndpoint { private final Collection scheduledTaskHolders; @@ -295,4 +301,16 @@ public class ScheduledTasksEndpoint { } + static class ScheduledTasksEndpointRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + this.bindingRegistrar.registerReflectionHints(hints.reflection(), FixedRateTaskDescription.class, + FixedDelayTaskDescription.class, CronTaskDescription.class, CustomTriggerTaskDescription.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/startup/StartupEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/startup/StartupEndpoint.java index 51b0412a651..e0c03227aab 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/startup/StartupEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/startup/StartupEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -16,12 +16,18 @@ package org.springframework.boot.actuate.startup; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; import org.springframework.boot.SpringBootVersion; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; +import org.springframework.boot.actuate.startup.StartupEndpoint.StartupEndpointRuntimeHints; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; import org.springframework.boot.context.metrics.buffering.StartupTimeline; +import org.springframework.context.annotation.ImportRuntimeHints; /** * {@link Endpoint @Endpoint} to expose the timeline of the @@ -33,6 +39,7 @@ import org.springframework.boot.context.metrics.buffering.StartupTimeline; * @since 2.4.0 */ @Endpoint(id = "startup") +@ImportRuntimeHints(StartupEndpointRuntimeHints.class) public class StartupEndpoint { private final BufferingApplicationStartup applicationStartup; @@ -83,4 +90,26 @@ public class StartupEndpoint { } + static class StartupEndpointRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerType( + TypeReference + .of("org.springframework.boot.context.metrics.buffering.BufferedStartupStep$DefaultTag"), + (hint) -> hint + .onReachableType(TypeReference + .of("org.springframework.boot.context.metrics.buffering.BufferedStartupStep")) + .withMembers(MemberCategory.INVOKE_PUBLIC_METHODS)); + hints.reflection().registerType( + TypeReference + .of("org.springframework.core.metrics.jfr.FlightRecorderStartupStep$FlightRecorderTag"), + (hint) -> hint + .onReachableType( + TypeReference.of("org.springframework.core.metrics.jfr.FlightRecorderStartupStep")) + .withMembers(MemberCategory.INVOKE_PUBLIC_METHODS)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProvider.java index 49ef3611851..67d6ad941a5 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -28,9 +28,14 @@ import java.util.stream.Stream; import reactor.core.publisher.Mono; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.web.mappings.HandlerMethodDescription; import org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider; +import org.springframework.boot.actuate.web.mappings.reactive.DispatcherHandlersMappingDescriptionProvider.DispatcherHandlersMappingDescriptionProviderRuntimeHints; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.core.io.Resource; import org.springframework.web.method.HandlerMethod; import org.springframework.web.reactive.DispatcherHandler; @@ -53,6 +58,7 @@ import org.springframework.web.util.pattern.PathPattern; * @author Andy Wilkinson * @since 2.0.0 */ +@ImportRuntimeHints(DispatcherHandlersMappingDescriptionProviderRuntimeHints.class) public class DispatcherHandlersMappingDescriptionProvider implements MappingDescriptionProvider { private static final List> descriptionProviders = Arrays @@ -194,4 +200,16 @@ public class DispatcherHandlersMappingDescriptionProvider implements MappingDesc } + static class DispatcherHandlersMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + this.bindingRegistrar.registerReflectionHints(hints.reflection(), + DispatcherHandlerMappingDescription.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java index 49b7e2ba3e5..18592a7a9ed 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java @@ -28,10 +28,15 @@ import java.util.stream.Stream; import jakarta.servlet.Servlet; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.web.mappings.HandlerMethodDescription; import org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider; +import org.springframework.boot.actuate.web.mappings.servlet.DispatcherServletsMappingDescriptionProvider.DispatcherServletsMappingDescriptionProviderRuntimeHints; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.DispatcherServlet; @@ -49,6 +54,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi * @author Stephane Nicoll * @since 2.0.0 */ +@ImportRuntimeHints(DispatcherServletsMappingDescriptionProviderRuntimeHints.class) public class DispatcherServletsMappingDescriptionProvider implements MappingDescriptionProvider { private static final List> descriptionProviders; @@ -195,4 +201,16 @@ public class DispatcherServletsMappingDescriptionProvider implements MappingDesc } + static class DispatcherServletsMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + this.bindingRegistrar.registerReflectionHints(hints.reflection(), + DispatcherServletMappingDescription.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProvider.java index c091d2dcfa1..a03ad253c88 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProvider.java @@ -23,8 +23,13 @@ import java.util.stream.Collectors; import jakarta.servlet.Filter; import jakarta.servlet.ServletContext; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider; +import org.springframework.boot.actuate.web.mappings.servlet.FiltersMappingDescriptionProvider.FiltersMappingDescriptionProviderRuntimeHints; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.web.context.WebApplicationContext; /** @@ -34,6 +39,7 @@ import org.springframework.web.context.WebApplicationContext; * @author Andy Wilkinson * @since 2.0.0 */ +@ImportRuntimeHints(FiltersMappingDescriptionProviderRuntimeHints.class) public class FiltersMappingDescriptionProvider implements MappingDescriptionProvider { @Override @@ -50,4 +56,16 @@ public class FiltersMappingDescriptionProvider implements MappingDescriptionProv return "servletFilters"; } + static class FiltersMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + this.bindingRegistrar.registerReflectionHints(hints.reflection(), + FilterRegistrationMappingDescription.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProvider.java index 8c36e618111..d9fa2a7e424 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProvider.java @@ -23,8 +23,13 @@ import java.util.stream.Collectors; import jakarta.servlet.Servlet; import jakarta.servlet.ServletContext; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider; +import org.springframework.boot.actuate.web.mappings.servlet.ServletsMappingDescriptionProvider.ServletsMappingDescriptionProviderRuntimeHints; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.context.aot.BindingReflectionHintsRegistrar; import org.springframework.web.context.WebApplicationContext; /** @@ -34,6 +39,7 @@ import org.springframework.web.context.WebApplicationContext; * @author Andy Wilkinson * @since 2.0.0 */ +@ImportRuntimeHints(ServletsMappingDescriptionProviderRuntimeHints.class) public class ServletsMappingDescriptionProvider implements MappingDescriptionProvider { @Override @@ -50,4 +56,16 @@ public class ServletsMappingDescriptionProvider implements MappingDescriptionPro return "servlets"; } + static class ServletsMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + this.bindingRegistrar.registerReflectionHints(hints.reflection(), + ServletRegistrationMappingDescription.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrarTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrarTests.java new file mode 100644 index 00000000000..9da4482ae02 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/aot/ActuatorAnnotationsRuntimeHintsRegistrarTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.aot; + +import java.util.Set; + +import org.junit.jupiter.api.BeforeEach; +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.boot.actuate.endpoint.annotation.DeleteOperation; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; +import org.springframework.core.annotation.SynthesizedAnnotation; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ActuatorAnnotationsRuntimeHintsRegistrar}. + * + * @author Moritz Halbritter + */ +class ActuatorAnnotationsRuntimeHintsRegistrarTests { + + private final ActuatorAnnotationsRuntimeHintsRegistrar sut = new ActuatorAnnotationsRuntimeHintsRegistrar(); + + private RuntimeHints runtimeHints; + + @BeforeEach + void setUp() { + this.runtimeHints = new RuntimeHints(); + this.sut.registerHints(this.runtimeHints, getClass().getClassLoader()); + } + + @Test + void shouldRegisterReflectionHints() { + Set> annotations = Set.of(Endpoint.class, ReadOperation.class, WriteOperation.class, + DeleteOperation.class, EndpointExtension.class); + for (Class annotation : annotations) { + assertThat(RuntimeHintsPredicates.reflection().onType(annotation) + .withAnyMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.runtimeHints); + } + } + + @Test + void shouldRegisterProxyHints() { + Set> synthesizedAnnotations = Set.of(Endpoint.class, EndpointExtension.class); + for (Class synthesizedAnnotation : synthesizedAnnotations) { + assertThat( + RuntimeHintsPredicates.proxies().forInterfaces(synthesizedAnnotation, SynthesizedAnnotation.class)) + .accepts(this.runtimeHints); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessorTests.java new file mode 100644 index 00000000000..dac08b3317a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessorTests.java @@ -0,0 +1,132 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.annotation; + +import java.lang.reflect.Method; + +import org.junit.jupiter.api.BeforeEach; +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.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.core.io.Resource; +import org.springframework.util.ReflectionUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OperationReflectiveProcessor}. + * + * @author Moritz Halbritter + */ +class OperationReflectiveProcessorTests { + + private final OperationReflectiveProcessor sut = new OperationReflectiveProcessor(); + + private RuntimeHints runtimeHints; + + @BeforeEach + void setUp() { + this.runtimeHints = new RuntimeHints(); + } + + @Test + void shouldRegisterMethodAsInvokable() { + Method method = ReflectionUtils.findMethod(Methods.class, "string"); + runProcessor(method); + assertThat(RuntimeHintsPredicates.reflection().onMethod(method)).accepts(this.runtimeHints); + } + + @Test + void shouldRegisterReturnType() { + Method method = ReflectionUtils.findMethod(Methods.class, "dto"); + runProcessor(method); + assertThat(RuntimeHintsPredicates.reflection().onType(Dto.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(this.runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(NestedDto.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(this.runtimeHints); + } + + @Test + void shouldRegisterWebEndpointResponseReturnType() { + Method method = ReflectionUtils.findMethod(Methods.class, "webEndpointResponse"); + runProcessor(method); + assertThat(RuntimeHintsPredicates.reflection().onType(Dto.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(this.runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(NestedDto.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(this.runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(WebEndpointResponse.class)).rejects(this.runtimeHints); + } + + @Test + void shouldNotRegisterResourceReturnType() { + Method method = ReflectionUtils.findMethod(Methods.class, "resource"); + runProcessor(method); + assertThat(RuntimeHintsPredicates.reflection().onType(Resource.class)).rejects(this.runtimeHints); + } + + private void runProcessor(Method method) { + this.sut.registerReflectionHints(this.runtimeHints.reflection(), method); + } + + private static class Methods { + + private String string() { + return null; + } + + private Dto dto() { + return null; + } + + private WebEndpointResponse webEndpointResponse() { + return null; + } + + private Resource resource() { + return null; + } + + } + + public static class Dto { + + private final NestedDto nestedDto = new NestedDto(); + + public NestedDto getNestedDto() { + return this.nestedDto; + } + + } + + public static class NestedDto { + + private final String string = "some-string"; + + public String getString() { + return this.string; + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererRuntimeHintsTests.java new file mode 100644 index 00000000000..5b039d186ab --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererRuntimeHintsTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.jmx.annotation; + +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.boot.actuate.endpoint.jmx.annotation.JmxEndpointDiscoverer.JmxEndpointDiscovererRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link JmxEndpointDiscovererRuntimeHints}. + * + * @author Moritz Halbritter + */ +class JmxEndpointDiscovererRuntimeHintsTests { + + private final JmxEndpointDiscovererRuntimeHints sut = new JmxEndpointDiscovererRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(JmxEndpointFilter.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererRuntimeHintsTests.java new file mode 100644 index 00000000000..dc7d674d4f2 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererRuntimeHintsTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.web.annotation; + +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.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer.ControllerEndpointDiscovererRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ControllerEndpointDiscovererRuntimeHints}. + * + * @author Moritz Halbritter + */ +class ControllerEndpointDiscovererRuntimeHintsTests { + + private final ControllerEndpointDiscovererRuntimeHints sut = new ControllerEndpointDiscovererRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(ControllerEndpointFilter.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints); + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererRuntimeHintsTests.java new file mode 100644 index 00000000000..43e2cb05063 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererRuntimeHintsTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.web.annotation; + +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.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer.ServletEndpointDiscovererRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ServletEndpointDiscovererRuntimeHints}. + * + * @author Moritz Halbritter + */ +class ServletEndpointDiscovererRuntimeHintsTests { + + private final ServletEndpointDiscovererRuntimeHints sut = new ServletEndpointDiscovererRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(ServletEndpointFilter.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints); + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererRuntimeHintsTests.java new file mode 100644 index 00000000000..255a0cff1fc --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererRuntimeHintsTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.web.annotation; + +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.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer.WebEndpointDiscovererRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebEndpointDiscovererRuntimeHints}. + * + * @author Moritz Halbritter + */ +class WebEndpointDiscovererRuntimeHintsTests { + + private final WebEndpointDiscovererRuntimeHints sut = new WebEndpointDiscovererRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(WebEndpointFilter.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints); + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMappingRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMappingRuntimeHintsTests.java new file mode 100644 index 00000000000..a33f8d0928e --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMappingRuntimeHintsTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.web.reactive; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link AbstractWebFluxEndpointHandlerMappingRuntimeHints}. + * + * @author Moritz Halbritter + */ +class AbstractWebFluxEndpointHandlerMappingRuntimeHintsTests { + + private final AbstractWebFluxEndpointHandlerMappingRuntimeHints sut = new AbstractWebFluxEndpointHandlerMappingRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of( + "org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.WriteOperationHandler"))) + .accepts(runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of( + "org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.ReadOperationHandler"))) + .accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMappingRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMappingRuntimeHintsTests.java new file mode 100644 index 00000000000..78077fc2573 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMappingRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.web.reactive; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.endpoint.web.Link; +import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints; +import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.WebFluxLinksHandler; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebFluxEndpointHandlerMappingRuntimeHints}. + * + * @author Moritz Halbritter + */ +class WebFluxEndpointHandlerMappingRuntimeHintsTests { + + private final WebFluxEndpointHandlerMappingRuntimeHints sut = new WebFluxEndpointHandlerMappingRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onMethod(WebFluxLinksHandler.class, "links")) + .accepts(runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMappingRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMappingRuntimeHintsTests.java new file mode 100644 index 00000000000..f51743f6dc4 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/AbstractWebMvcEndpointHandlerMappingRuntimeHintsTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.web.servlet; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link AbstractWebMvcEndpointHandlerMappingRuntimeHints}. + * + * @author Moritz Halbritter + */ +class AbstractWebMvcEndpointHandlerMappingRuntimeHintsTests { + + private final AbstractWebMvcEndpointHandlerMappingRuntimeHints sut = new AbstractWebMvcEndpointHandlerMappingRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of( + "org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler"))) + .accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMappingRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMappingRuntimeHintsTests.java new file mode 100644 index 00000000000..6351d89e46d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcEndpointHandlerMappingRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.web.servlet; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.endpoint.web.Link; +import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints; +import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.WebMvcLinksHandler; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebMvcEndpointHandlerMappingRuntimeHints}. + * + * @author Moritz Halbritter + */ +class WebMvcEndpointHandlerMappingRuntimeHintsTests { + + private final WebMvcEndpointHandlerMappingRuntimeHints sut = new WebMvcEndpointHandlerMappingRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onMethod(WebMvcLinksHandler.class, "links")) + .accepts(runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionRuntimeHintsTests.java new file mode 100644 index 00000000000..89c4a260c11 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionRuntimeHintsTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.health; + +import java.util.Set; + +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.boot.actuate.health.HealthEndpointWebExtension.HealthEndpointWebExtensionRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link HealthEndpointWebExtensionRuntimeHints}. + * + * @author Moritz Halbritter + */ +class HealthEndpointWebExtensionRuntimeHintsTests { + + private final HealthEndpointWebExtensionRuntimeHints sut = new HealthEndpointWebExtensionRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + Set> bindingTypes = Set.of(Health.class, SystemHealth.class, CompositeHealth.class); + for (Class bindingType : bindingTypes) { + assertThat(RuntimeHintsPredicates.reflection().onType(bindingType) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/BuildInfoContributorRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/BuildInfoContributorRuntimeHintsTests.java new file mode 100644 index 00000000000..aa1af63019a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/BuildInfoContributorRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.info; + +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.boot.actuate.info.BuildInfoContributor.BuildInfoContributorRuntimeHints; +import org.springframework.boot.info.BuildProperties; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link BuildInfoContributorRuntimeHints}. + * + * @author Moritz Halbritter + */ +class BuildInfoContributorRuntimeHintsTests { + + private final BuildInfoContributorRuntimeHints sut = new BuildInfoContributorRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(BuildProperties.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/GitInfoContributorRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/GitInfoContributorRuntimeHintsTests.java new file mode 100644 index 00000000000..fd2e1f1c170 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/GitInfoContributorRuntimeHintsTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.info; + +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.boot.actuate.info.GitInfoContributor.GitInfoContributorRuntimeHints; +import org.springframework.boot.info.GitProperties; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests forr {@link GitInfoContributorRuntimeHints}. + * + * @author Moritz Halbritter + */ +class GitInfoContributorRuntimeHintsTests { + + private final GitInfoContributorRuntimeHints sut = new GitInfoContributorRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(GitProperties.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/JavaInfoContributorRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/JavaInfoContributorRuntimeHintsTests.java new file mode 100644 index 00000000000..7490ac60a69 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/JavaInfoContributorRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.info; + +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.boot.actuate.info.JavaInfoContributor.JavaInfoContributorRuntimeHints; +import org.springframework.boot.info.JavaInfo; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link JavaInfoContributorRuntimeHints}. + * + * @author Moritz Halbritter + */ +class JavaInfoContributorRuntimeHintsTests { + + private final JavaInfoContributorRuntimeHints sut = new JavaInfoContributorRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(JavaInfo.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorRuntimeHintsTests.java new file mode 100644 index 00000000000..893daa341ed --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorRuntimeHintsTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.info; + +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.boot.actuate.info.OsInfoContributor.OsInfoContributorRuntimeHints; +import org.springframework.boot.info.OsInfo; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OsInfoContributorRuntimeHints}. + * + * @author Moritz Halbritter + */ +class OsInfoContributorRuntimeHintsTests { + + private final OsInfoContributorRuntimeHints sut = new OsInfoContributorRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(OsInfo.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointRuntimeHintsTests.java new file mode 100644 index 00000000000..51d7e7c0761 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointRuntimeHintsTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.integration; + +import java.util.Set; + +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.boot.actuate.integration.IntegrationGraphEndpoint.IntegrationGraphEndpointRuntimeHints; +import org.springframework.integration.graph.CompositeMessageHandlerNode; +import org.springframework.integration.graph.DiscardingMessageHandlerNode; +import org.springframework.integration.graph.EndpointNode; +import org.springframework.integration.graph.ErrorCapableCompositeMessageHandlerNode; +import org.springframework.integration.graph.ErrorCapableDiscardingMessageHandlerNode; +import org.springframework.integration.graph.ErrorCapableEndpointNode; +import org.springframework.integration.graph.ErrorCapableMessageHandlerNode; +import org.springframework.integration.graph.ErrorCapableRoutingNode; +import org.springframework.integration.graph.Graph; +import org.springframework.integration.graph.MessageChannelNode; +import org.springframework.integration.graph.MessageGatewayNode; +import org.springframework.integration.graph.MessageHandlerNode; +import org.springframework.integration.graph.MessageProducerNode; +import org.springframework.integration.graph.MessageSourceNode; +import org.springframework.integration.graph.PollableChannelNode; +import org.springframework.integration.graph.RoutingMessageHandlerNode; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link IntegrationGraphEndpointRuntimeHints}. + * + * @author Moritz Halbritter + */ +class IntegrationGraphEndpointRuntimeHintsTests { + + private final IntegrationGraphEndpointRuntimeHints sut = new IntegrationGraphEndpointRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + Set> bindingTypes = Set.of(Graph.class, EndpointNode.class, CompositeMessageHandlerNode.class, + DiscardingMessageHandlerNode.class, ErrorCapableCompositeMessageHandlerNode.class, + ErrorCapableDiscardingMessageHandlerNode.class, ErrorCapableEndpointNode.class, + ErrorCapableMessageHandlerNode.class, ErrorCapableRoutingNode.class, MessageGatewayNode.class, + MessageProducerNode.class, PollableChannelNode.class, MessageChannelNode.class, + MessageHandlerNode.class, MessageSourceNode.class, RoutingMessageHandlerNode.class); + for (Class bindingType : bindingTypes) { + assertThat(RuntimeHintsPredicates.reflection().onType(bindingType) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtensionTests.java new file mode 100644 index 00000000000..c0735584025 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebExtensionTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.management; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.boot.actuate.management.ThreadDumpEndpoint.ThreadDumpDescriptor; +import org.springframework.boot.actuate.management.ThreadDumpEndpoint.ThreadDumperUnavailableException; +import org.springframework.http.HttpStatus; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ThreadDumpEndpointWebExtension}. + * + * @author Moritz Halbritter + */ +class ThreadDumpEndpointWebExtensionTests { + + private ThreadDumpEndpointWebExtension sut; + + private ThreadDumpEndpoint delegateMock; + + @BeforeEach + void setUp() { + this.delegateMock = Mockito.mock(ThreadDumpEndpoint.class); + this.sut = new ThreadDumpEndpointWebExtension(this.delegateMock); + } + + @Test + void shouldHandleThreadDumperUnavailable() { + Mockito.when(this.delegateMock.threadDump()) + .thenThrow(new ThreadDumperUnavailableException("No thread dumper available")); + WebEndpointResponse response = this.sut.threadDump(); + assertThat(response.getStatus()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value()); + } + + @Test + void shouldHandleThreadDumperUnavailableText() { + Mockito.when(this.delegateMock.textThreadDump()) + .thenThrow(new ThreadDumperUnavailableException("No thread dumper available")); + WebEndpointResponse response = this.sut.textThreadDump(); + assertThat(response.getStatus()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProviderRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProviderRuntimeHintsTests.java new file mode 100644 index 00000000000..7101421547d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/cache/HazelcastCacheMeterBinderProviderRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.metrics.cache; + +import com.hazelcast.spring.cache.HazelcastCache; +import io.micrometer.core.instrument.binder.cache.HazelcastCacheMetrics; +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.metrics.cache.HazelcastCacheMeterBinderProvider.HazelcastCacheMeterBinderProviderRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link HazelcastCacheMeterBinderProviderRuntimeHints}. + * + * @author Moritz Halbritter + */ +class HazelcastCacheMeterBinderProviderRuntimeHintsTests { + + private final HazelcastCacheMeterBinderProviderRuntimeHints sut = new HazelcastCacheMeterBinderProviderRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onMethod(HazelcastCache.class, "getNativeCache")) + .accepts(runtimeHints); + assertThat(RuntimeHintsPredicates.reflection().onType(HazelcastCacheMetrics.class)).accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtensionRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtensionRuntimeHintsTests.java new file mode 100644 index 00000000000..503424683ac --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/quartz/QuartzEndpointWebExtensionRuntimeHintsTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.quartz; + +import java.util.Set; + +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.boot.actuate.quartz.QuartzEndpoint.QuartzGroups; +import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzJobDetails; +import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzJobGroupSummary; +import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzTriggerGroupSummary; +import org.springframework.boot.actuate.quartz.QuartzEndpointWebExtension.QuartzEndpointWebExtensionRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link QuartzEndpointWebExtensionRuntimeHints}. + * + * @author Moritz Halbritter + */ +class QuartzEndpointWebExtensionRuntimeHintsTests { + + private final QuartzEndpointWebExtensionRuntimeHints sut = new QuartzEndpointWebExtensionRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + Set> bindingTypes = Set.of(QuartzGroups.class, QuartzJobDetails.class, QuartzJobGroupSummary.class, + QuartzTriggerGroupSummary.class); + for (Class bindingType : bindingTypes) { + assertThat(RuntimeHintsPredicates.reflection().onType(bindingType) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpointRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpointRuntimeHintsTests.java new file mode 100644 index 00000000000..d2273476550 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpointRuntimeHintsTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.scheduling; + +import java.util.Set; + +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.boot.actuate.scheduling.ScheduledTasksEndpoint.CronTaskDescription; +import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.CustomTriggerTaskDescription; +import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.FixedDelayTaskDescription; +import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.FixedRateTaskDescription; +import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksEndpointRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ScheduledTasksEndpointRuntimeHints}. + * + * @author Moritz Halbritter + */ +class ScheduledTasksEndpointRuntimeHintsTests { + + private final ScheduledTasksEndpointRuntimeHints sut = new ScheduledTasksEndpointRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + Set> bindingTypes = Set.of(FixedRateTaskDescription.class, FixedDelayTaskDescription.class, + CronTaskDescription.class, CustomTriggerTaskDescription.class); + for (Class bindingType : bindingTypes) { + assertThat(RuntimeHintsPredicates.reflection().onType(bindingType) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/startup/StartupEndpointRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/startup/StartupEndpointRuntimeHintsTests.java new file mode 100644 index 00000000000..bc65478ab7a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/startup/StartupEndpointRuntimeHintsTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.startup; + +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.actuate.startup.StartupEndpoint.StartupEndpointRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link StartupEndpointRuntimeHints}. + * + * @author Moritz Halbritter + */ +class StartupEndpointRuntimeHintsTests { + + private final StartupEndpointRuntimeHints sut = new StartupEndpointRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + Set bindingTypes = Set.of( + TypeReference.of("org.springframework.boot.context.metrics.buffering.BufferedStartupStep$DefaultTag"), + TypeReference.of("org.springframework.core.metrics.jfr.FlightRecorderStartupStep$FlightRecorderTag")); + for (TypeReference bindingType : bindingTypes) { + assertThat(RuntimeHintsPredicates.reflection().onType(bindingType) + .withMemberCategories(MemberCategory.INVOKE_PUBLIC_METHODS)).accepts(runtimeHints); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProviderRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProviderRuntimeHintsTests.java new file mode 100644 index 00000000000..990d9aa85bb --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProviderRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.web.mappings.reactive; + +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.boot.actuate.web.mappings.reactive.DispatcherHandlersMappingDescriptionProvider.DispatcherHandlersMappingDescriptionProviderRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DispatcherHandlersMappingDescriptionProviderRuntimeHints}. + * + * @author Moritz Halbritter + */ +class DispatcherHandlersMappingDescriptionProviderRuntimeHintsTests { + + private final DispatcherHandlersMappingDescriptionProviderRuntimeHints sut = new DispatcherHandlersMappingDescriptionProviderRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(DispatcherHandlerMappingDescription.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProviderRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProviderRuntimeHintsTests.java new file mode 100644 index 00000000000..b7b58cc135d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProviderRuntimeHintsTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.web.mappings.servlet; + +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.boot.actuate.web.mappings.servlet.DispatcherServletsMappingDescriptionProvider.DispatcherServletsMappingDescriptionProviderRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DispatcherServletsMappingDescriptionProviderRuntimeHints}. + * + * @author Moritz Halbritter + */ +class DispatcherServletsMappingDescriptionProviderRuntimeHintsTests { + + private final DispatcherServletsMappingDescriptionProviderRuntimeHints sut = new DispatcherServletsMappingDescriptionProviderRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(DispatcherServletMappingDescription.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProviderRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProviderRuntimeHintsTests.java new file mode 100644 index 00000000000..81e6ae5f076 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProviderRuntimeHintsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.web.mappings.servlet; + +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.boot.actuate.web.mappings.servlet.FiltersMappingDescriptionProvider.FiltersMappingDescriptionProviderRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link FiltersMappingDescriptionProviderRuntimeHints}. + * + * @author Moritz Halbritter + */ +class FiltersMappingDescriptionProviderRuntimeHintsTests { + + private final FiltersMappingDescriptionProviderRuntimeHints sut = new FiltersMappingDescriptionProviderRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(FilterRegistrationMappingDescription.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProviderRuntimeHintsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProviderRuntimeHintsTests.java new file mode 100644 index 00000000000..aa19dadc420 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProviderRuntimeHintsTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.web.mappings.servlet; + +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.boot.actuate.web.mappings.servlet.ServletsMappingDescriptionProvider.ServletsMappingDescriptionProviderRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ServletsMappingDescriptionProviderRuntimeHints}. + * + * @author Moritz Halbritter + */ +class ServletsMappingDescriptionProviderRuntimeHintsTests { + + private final ServletsMappingDescriptionProviderRuntimeHints sut = new ServletsMappingDescriptionProviderRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.reflection().onType(ServletRegistrationMappingDescription.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)) + .accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/BuildProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/BuildProperties.java index 76ec3485aaf..efbc13065a3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/BuildProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/BuildProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -21,12 +21,18 @@ import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.Properties; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.boot.info.BuildProperties.BuildPropertiesRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; + /** * Provide build-related information such as group and artifact. * * @author Stephane Nicoll * @since 1.4.0 */ +@ImportRuntimeHints(BuildPropertiesRuntimeHints.class) public class BuildProperties extends InfoProperties { /** @@ -100,4 +106,13 @@ public class BuildProperties extends InfoProperties { } } + static class BuildPropertiesRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.resources().registerPattern("META-INF/build-info.properties"); + } + + } + } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/GitProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/GitProperties.java index d07f6cf88d7..ba5aff3c9c7 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/GitProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/GitProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -21,12 +21,18 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Properties; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.boot.info.GitProperties.GitPropertiesRuntimeHints; +import org.springframework.context.annotation.ImportRuntimeHints; + /** * Provide git-related information such as commit id and time. * * @author Stephane Nicoll * @since 1.4.0 */ +@ImportRuntimeHints(GitPropertiesRuntimeHints.class) public class GitProperties extends InfoProperties { public GitProperties(Properties entries) { @@ -126,4 +132,13 @@ public class GitProperties extends InfoProperties { } } + static class GitPropertiesRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.resources().registerPattern("git.properties"); + } + + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/BuildPropertiesRuntimeHintsTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/BuildPropertiesRuntimeHintsTests.java new file mode 100644 index 00000000000..e8be5ba690f --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/BuildPropertiesRuntimeHintsTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.info; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.info.BuildProperties.BuildPropertiesRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link BuildPropertiesRuntimeHints}. + * + * @author Moritz Halbritter + */ +class BuildPropertiesRuntimeHintsTests { + + private final BuildPropertiesRuntimeHints sut = new BuildPropertiesRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.resource().forResource("META-INF/build-info.properties")) + .accepts(runtimeHints); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesRuntimeHintsTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesRuntimeHintsTests.java new file mode 100644 index 00000000000..93de2c71a40 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesRuntimeHintsTests.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.info; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.info.GitProperties.GitPropertiesRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link GitPropertiesRuntimeHints}. + * + * @author Moritz Halbritter + */ +class GitPropertiesRuntimeHintsTests { + + private final GitPropertiesRuntimeHints sut = new GitPropertiesRuntimeHints(); + + @Test + void shouldRegisterHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + this.sut.registerHints(runtimeHints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.resource().forResource("git.properties")).accepts(runtimeHints); + } + +}