Merge pull request #31671 from mhalbritter

* pr/31671:
  Polish "Add AOT support for actuator"
  Add AOT support for actuator

Closes gh-31671
This commit is contained in:
Stephane Nicoll
2022-07-19 13:10:23 +02:00
69 changed files with 1869 additions and 38 deletions

View File

@@ -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));
}
}
}

View File

@@ -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.
@@ -20,13 +20,17 @@ import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
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,9 +39,12 @@ 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;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
@@ -50,6 +57,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 +153,17 @@ 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().registerMethod(Objects.requireNonNull(
ReflectionUtils.findMethod(CloudFoundryLinksHandler.class, "links", ServerWebExchange.class)));
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}
}
}

View File

@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletRequest;
@@ -27,8 +28,11 @@ import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
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,8 +41,11 @@ 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.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
@@ -51,6 +58,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 +155,18 @@ 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()
.registerMethod(Objects.requireNonNull(ReflectionUtils.findMethod(CloudFoundryLinksHandler.class,
"links", HttpServletRequest.class, HttpServletResponse.class)));
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}
}
}

View File

@@ -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.autoconfigure.endpoint;
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;
/**
* {@link RuntimeHintsRegistrar} for actuator support.
*
* @author Moritz Halbritter
*/
class ActuatorAnnotationsRuntimeHints 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));
}
}

View File

@@ -30,6 +30,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 +46,7 @@ import org.springframework.core.env.Environment;
* @since 2.0.0
*/
@AutoConfiguration
@ImportRuntimeHints(ActuatorAnnotationsRuntimeHints.class)
public class EndpointAutoConfiguration {
@Bean

View File

@@ -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);
}
}

View File

@@ -23,6 +23,10 @@ import java.util.function.Function;
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 org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.SecurityContext;
@@ -50,6 +54,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link CloudFoundryWebEndpointDiscoverer}.
*
* @author Madhura Bhave
* @author Moritz Halbritter
*/
class CloudFoundryWebEndpointDiscovererTests {
@@ -69,6 +74,14 @@ class CloudFoundryWebEndpointDiscovererTests {
});
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new CloudFoundryWebEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(CloudFoundryEndpointFilter.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);
}
private WebOperation findMainReadOperation(ExposableWebEndpoint endpoint) {
for (WebOperation operation : endpoint.getOperations()) {
if (operation.getRequestPredicate().getPath().equals("health")) {

View File

@@ -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.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 CloudFoundryWebFluxEndpointHandlerMapping}.
*
* @author Moritz Halbritter
*/
class CloudFoundryWebFluxEndpointHandlerMappingTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints,
getClass().getClassLoader());
Assertions.assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links"))
.accepts(runtimeHints);
Assertions.assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
}
}

View File

@@ -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.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 CloudFoundryWebEndpointServletHandlerMapping}.
*
* @author Moritz Halbritter
*/
class CloudFoundryWebEndpointServletHandlerMappingTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new CloudFoundryWebEndpointServletHandlerMappingRuntimeHints().registerHints(runtimeHints,
getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links"))
.accepts(runtimeHints);
assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
}
}

View File

@@ -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.autoconfigure.endpoint;
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 ActuatorAnnotationsRuntimeHints}.
*
* @author Moritz Halbritter
*/
class ActuatorAnnotationsRuntimeHintsTests {
private final ActuatorAnnotationsRuntimeHints registrar = new ActuatorAnnotationsRuntimeHints();
private RuntimeHints runtimeHints;
@BeforeEach
void setUp() {
this.runtimeHints = new RuntimeHints();
this.registrar.registerHints(this.runtimeHints, getClass().getClassLoader());
}
@Test
void shouldRegisterReflectionHints() {
Set<Class<?>> 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<Class<?>> synthesizedAnnotations = Set.of(Endpoint.class, EndpointExtension.class);
for (Class<?> synthesizedAnnotation : synthesizedAnnotations) {
assertThat(
RuntimeHintsPredicates.proxies().forInterfaces(synthesizedAnnotation, SynthesizedAnnotation.class))
.accepts(this.runtimeHints);
}
}
}

View File

@@ -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);
});
}
}

View File

@@ -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 {
/**

View File

@@ -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 {
/**

View File

@@ -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 {
/**

View File

@@ -0,0 +1,65 @@
/*
* 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 java.lang.reflect.Type;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.annotation.ReflectiveProcessor;
import org.springframework.aot.hint.annotation.SimpleReflectiveProcessor;
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;
/**
* {@link ReflectiveProcessor} that registers the annotated operation method and its
* return type for reflection.
*
* @author Moritz Halbritter
* @author Stephane Nicoll
*/
class OperationReflectiveProcessor extends SimpleReflectiveProcessor {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
protected void registerMethodHint(ReflectionHints hints, Method method) {
super.registerMethodHint(hints, method);
Type returnType = extractReturnType(method);
if (returnType != null) {
registerReflectionHints(hints, returnType);
}
}
private Type extractReturnType(Method method) {
ResolvableType returnType = ResolvableType.forMethodReturnType(method);
if (WebEndpointResponse.class.isAssignableFrom(method.getReturnType())) {
return returnType.as(WebEndpointResponse.class).getGeneric(0).getType();
}
return returnType.getType();
}
private void registerReflectionHints(ReflectionHints hints, Type type) {
if (type.equals(Resource.class)) {
return;
}
this.bindingRegistrar.registerReflectionHints(hints, type);
}
}

View File

@@ -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 {
/**

View File

@@ -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 {
/**

View File

@@ -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<ExposableJmxEndpoint, JmxOperation>
implements JmxEndpointsSupplier {
@@ -69,4 +75,14 @@ public class JmxEndpointDiscoverer extends EndpointDiscoverer<ExposableJmxEndpoi
return new OperationKey(operation.getName(), () -> "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));
}
}
}

View File

@@ -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<ExposableControllerEndpoint, Operation>
implements ControllerEndpointsSupplier {
@@ -80,4 +86,14 @@ public class ControllerEndpointDiscoverer extends EndpointDiscoverer<ExposableCo
throw new IllegalStateException("ControllerEndpoints must not declare operations");
}
static class ControllerEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(ControllerEndpointFilter.class,
(hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
}
}
}

View File

@@ -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<ExposableServletEndpoint, Operation>
implements ServletEndpointsSupplier {
@@ -79,4 +85,14 @@ public class ServletEndpointDiscoverer extends EndpointDiscoverer<ExposableServl
throw new IllegalStateException("ServletEndpoints must not declare operations");
}
static class ServletEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(ServletEndpointFilter.class,
(hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
}
}
}

View File

@@ -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<ExposableWebEndpoint, WebOperation>
implements WebEndpointsSupplier {
@@ -87,4 +93,14 @@ public class WebEndpointDiscoverer extends EndpointDiscoverer<ExposableWebEndpoi
() -> "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));
}
}
}

View File

@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
@@ -30,6 +31,8 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationArgumentResolver;
@@ -44,7 +47,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 +85,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 +490,17 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
}
static class AbstractWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection()
.registerMethod(Objects.requireNonNull(ReflectionUtils.findMethod(WriteOperationHandler.class,
"handle", ServerWebExchange.class, Map.class)))
.registerMethod(Objects.requireNonNull(
ReflectionUtils.findMethod(ReadOperationHandler.class, "handle", ServerWebExchange.class)));
}
}
}

View File

@@ -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,13 +19,20 @@ package org.springframework.boot.actuate.endpoint.web.reactive;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
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.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.reactive.HandlerMapping;
@@ -41,6 +48,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 +97,17 @@ 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().registerMethod(Objects.requireNonNull(
ReflectionUtils.findMethod(WebFluxLinksHandler.class, "links", ServerWebExchange.class)));
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}
}
}

View File

@@ -26,12 +26,15 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import reactor.core.publisher.Flux;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext;
@@ -46,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.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 +85,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 +482,14 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
}
static class AbstractWebMvcEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerMethod(Objects.requireNonNull(
ReflectionUtils.findMethod(OperationHandler.class, "handle", HttpServletRequest.class, Map.class)));
}
}
}

View File

@@ -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.
@@ -19,15 +19,22 @@ package org.springframework.boot.actuate.endpoint.web.servlet;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
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.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.HandlerMapping;
@@ -40,6 +47,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 +94,18 @@ 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()
.registerMethod(Objects.requireNonNull(ReflectionUtils.findMethod(WebMvcLinksHandler.class, "links",
HttpServletRequest.class, HttpServletResponse.class)));
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}
}
}

View File

@@ -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<HealthContributor, HealthComponent> {
private static final String[] NO_PATH = {};
@@ -110,4 +116,16 @@ public class HealthEndpointWebExtension extends HealthEndpointSupport<HealthCont
return getCompositeHealth(apiVersion, contributions, statusAggregator, showComponents, groupNames);
}
static class HealthEndpointWebExtensionRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Health.class, SystemHealth.class,
CompositeHealth.class);
}
}
}

View File

@@ -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,7 +19,12 @@ package org.springframework.boot.actuate.info;
import java.util.Map;
import java.util.Properties;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.info.BuildInfoContributor.BuildInfoContributorRuntimeHints;
import org.springframework.boot.info.BuildProperties;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
@@ -29,6 +34,7 @@ import org.springframework.core.env.PropertySource;
* @author Stephane Nicoll
* @since 1.4.0
*/
@ImportRuntimeHints(BuildInfoContributorRuntimeHints.class)
public class BuildInfoContributor extends InfoPropertiesInfoContributor<BuildProperties> {
public BuildInfoContributor(BuildProperties properties) {
@@ -56,4 +62,15 @@ public class BuildInfoContributor extends InfoPropertiesInfoContributor<BuildPro
replaceValue(content, "time", getProperties().getTime());
}
static class BuildInfoContributorRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(), BuildProperties.class);
}
}
}

View File

@@ -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.
@@ -20,7 +20,12 @@ import java.time.Instant;
import java.util.Map;
import java.util.Properties;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.info.GitInfoContributor.GitInfoContributorRuntimeHints;
import org.springframework.boot.info.GitProperties;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
@@ -30,6 +35,7 @@ import org.springframework.core.env.PropertySource;
* @author Stephane Nicoll
* @since 1.4.0
*/
@ImportRuntimeHints(GitInfoContributorRuntimeHints.class)
public class GitInfoContributor extends InfoPropertiesInfoContributor<GitProperties> {
public GitInfoContributor(GitProperties properties) {
@@ -68,4 +74,15 @@ public class GitInfoContributor extends InfoPropertiesInfoContributor<GitPropert
replaceValue(getNestedMap(content, "build"), "time", getProperties().getInstant("build.time"));
}
static class GitInfoContributorRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(), GitProperties.class);
}
}
}

View File

@@ -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,8 +16,13 @@
package org.springframework.boot.actuate.info;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.info.Info.Builder;
import org.springframework.boot.actuate.info.JavaInfoContributor.JavaInfoContributorRuntimeHints;
import org.springframework.boot.info.JavaInfo;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
/**
* An {@link InfoContributor} that exposes {@link JavaInfo}.
@@ -25,6 +30,7 @@ import org.springframework.boot.info.JavaInfo;
* @author Jonatan Ivanov
* @since 2.6.0
*/
@ImportRuntimeHints(JavaInfoContributorRuntimeHints.class)
public class JavaInfoContributor implements InfoContributor {
private final JavaInfo javaInfo;
@@ -38,4 +44,15 @@ public class JavaInfoContributor implements InfoContributor {
builder.withDetail("java", this.javaInfo);
}
static class JavaInfoContributorRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(), JavaInfo.class);
}
}
}

View File

@@ -16,7 +16,12 @@
package org.springframework.boot.actuate.info;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.info.OsInfoContributor.OsInfoContributorRuntimeHints;
import org.springframework.boot.info.OsInfo;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
/**
* An {@link InfoContributor} that exposes {@link OsInfo}.
@@ -24,6 +29,7 @@ import org.springframework.boot.info.OsInfo;
* @author Jonatan Ivanov
* @since 2.7.0
*/
@ImportRuntimeHints(OsInfoContributorRuntimeHints.class)
public class OsInfoContributor implements InfoContributor {
private final OsInfo osInfo;
@@ -37,4 +43,15 @@ public class OsInfoContributor implements InfoContributor {
builder.withDetail("os", this.osInfo);
}
static class OsInfoContributorRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(), OsInfo.class);
}
}
}

View File

@@ -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.
@@ -16,11 +16,31 @@
package org.springframework.boot.actuate.integration;
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.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint.IntegrationGraphEndpointRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
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.IntegrationGraphServer;
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;
/**
* {@link Endpoint @Endpoint} to expose the Spring Integration graph.
@@ -29,6 +49,7 @@ import org.springframework.integration.graph.IntegrationGraphServer;
* @since 2.1.0
*/
@Endpoint(id = "integrationgraph")
@ImportRuntimeHints(IntegrationGraphEndpointRuntimeHints.class)
public class IntegrationGraphEndpoint {
private final IntegrationGraphServer graphServer;
@@ -53,4 +74,21 @@ public class IntegrationGraphEndpoint {
this.graphServer.rebuild();
}
static class IntegrationGraphEndpointRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Graph.class,
CompositeMessageHandlerNode.class, DiscardingMessageHandlerNode.class, EndpointNode.class,
ErrorCapableCompositeMessageHandlerNode.class, ErrorCapableDiscardingMessageHandlerNode.class,
ErrorCapableEndpointNode.class, ErrorCapableMessageHandlerNode.class, ErrorCapableRoutingNode.class,
MessageChannelNode.class, MessageGatewayNode.class, MessageHandlerNode.class,
MessageProducerNode.class, MessageSourceNode.class, PollableChannelNode.class,
RoutingMessageHandlerNode.class);
}
}
}

View File

@@ -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.
@@ -24,6 +24,7 @@ import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.core.NativeDetector;
/**
* {@link Endpoint @Endpoint} to expose thread info.
@@ -48,7 +49,41 @@ public class ThreadDumpEndpoint {
}
private <T> T getFormattedThreadDump(Function<ThreadInfo[], T> 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);
}
}
/**

View File

@@ -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<ThreadDumpDescriptor> 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<String> textThreadDump() {
try {
return new WebEndpointResponse<>(this.delegate.textThreadDump());
}
catch (ThreadDumperUnavailableException ex) {
return new WebEndpointResponse<>(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);
}
}
}

View File

@@ -17,12 +17,17 @@
package org.springframework.boot.actuate.metrics.cache;
import java.lang.reflect.Method;
import java.util.Objects;
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.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.metrics.cache.HazelcastCacheMeterBinderProvider.HazelcastCacheMeterBinderProviderRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.util.ReflectionUtils;
/**
@@ -31,6 +36,7 @@ import org.springframework.util.ReflectionUtils;
* @author Stephane Nicoll
* @since 2.0.0
*/
@ImportRuntimeHints(HazelcastCacheMeterBinderProviderRuntimeHints.class)
public class HazelcastCacheMeterBinderProvider implements CacheMeterBinderProvider<HazelcastCache> {
@Override
@@ -56,4 +62,22 @@ public class HazelcastCacheMeterBinderProvider implements CacheMeterBinderProvid
}
}
static class HazelcastCacheMeterBinderProviderRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
try {
hints.reflection()
.registerMethod(Objects
.requireNonNull(ReflectionUtils.findMethod(HazelcastCache.class, "getNativeCache")))
.registerConstructor(HazelcastCacheMetrics.class.getConstructor(Object.class, Iterable.class));
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException(ex);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<ScheduledTaskHolder> 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);
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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<HandlerMappingDescriptionProvider<? extends HandlerMapping>> 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);
}
}
}

View File

@@ -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<HandlerMappingDescriptionProvider<?>> 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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,141 @@
/*
* 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 java.util.List;
import java.util.Map;
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
* @author Stephane Nicoll
*/
class OperationReflectiveProcessorTests {
private final OperationReflectiveProcessor processor = new OperationReflectiveProcessor();
private final RuntimeHints 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);
assertHintsForDto();
}
@Test
void shouldRegisterMapValueFromReturnType() {
Method method = ReflectionUtils.findMethod(Methods.class, "dtos");
runProcessor(method);
assertHintsForDto();
}
@Test
void shouldRegisterWebEndpointResponseReturnType() {
Method method = ReflectionUtils.findMethod(Methods.class, "webEndpointResponse");
runProcessor(method);
assertHintsForDto();
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 assertHintsForDto() {
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);
}
private void runProcessor(Method method) {
this.processor.registerReflectionHints(this.runtimeHints.reflection(), method);
}
@SuppressWarnings("unused")
private static class Methods {
private String string() {
return null;
}
private Map<String, List<Dto>> dtos() {
return null;
}
private Dto dto() {
return null;
}
private WebEndpointResponse<Dto> webEndpointResponse() {
return null;
}
private Resource resource() {
return null;
}
}
@SuppressWarnings("unused")
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;
}
}
}

View File

@@ -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.
@@ -26,6 +26,9 @@ import java.util.function.Function;
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.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
@@ -37,6 +40,7 @@ import org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationI
import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;
import org.springframework.boot.actuate.endpoint.jmx.JmxOperation;
import org.springframework.boot.actuate.endpoint.jmx.JmxOperationParameter;
import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointDiscoverer.JmxEndpointDiscovererRuntimeHints;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -55,6 +59,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Moritz Halbritter
*/
class JmxEndpointDiscovererTests {
@@ -201,6 +206,14 @@ class JmxEndpointDiscovererTests {
"Endpoint bean 'nonJmxEndpoint' cannot support the extension bean 'nonJmxJmxEndpointExtension'"));
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new JmxEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(JmxEndpointFilter.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);
}
private Object getInvoker(JmxOperation operation) {
return ReflectionTestUtils.getField(operation, "invoker");
}

View File

@@ -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.
@@ -24,10 +24,14 @@ import java.util.stream.Collectors;
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.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer.ControllerEndpointDiscovererRuntimeHints;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
@@ -45,6 +49,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class ControllerEndpointDiscovererTests {
@@ -126,6 +131,15 @@ class ControllerEndpointDiscovererTests {
.withMessageContaining("ControllerEndpoints must not declare operations")));
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new ControllerEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(ControllerEndpointFilter.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);
}
private ContextConsumer<AssertableApplicationContext> assertDiscoverer(
Consumer<ControllerEndpointDiscoverer> consumer) {
return (context) -> {

View File

@@ -30,12 +30,16 @@ import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
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.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer.ServletEndpointDiscovererRuntimeHints;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
@@ -53,6 +57,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class ServletEndpointDiscovererTests {
@@ -129,6 +134,14 @@ class ServletEndpointDiscovererTests {
.isThrownBy(discoverer::getEndpoints).withMessageContaining("must not supply null")));
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new ServletEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(ServletEndpointFilter.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);
}
private ContextConsumer<AssertableApplicationContext> assertDiscoverer(
Consumer<ServletEndpointDiscoverer> consumer) {
return (context) -> {

View File

@@ -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.
@@ -31,6 +31,9 @@ import java.util.stream.Stream;
import org.assertj.core.api.Condition;
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.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
@@ -47,6 +50,7 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;
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.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -65,6 +69,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Phillip Webb
* @author Moritz Halbritter
*/
class WebEndpointDiscovererTests {
@@ -216,6 +221,15 @@ class WebEndpointDiscovererTests {
});
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new WebEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(WebEndpointFilter.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);
}
private void load(Class<?> configuration, Consumer<WebEndpointDiscoverer> consumer) {
load((id) -> null, EndpointId::toString, configuration, consumer);
}

View File

@@ -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.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 AbstractWebFluxEndpointHandlerMapping}.
*
* @author Moritz Halbritter
*/
class AbstractWebFluxEndpointHandlerMappingTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new AbstractWebFluxEndpointHandlerMappingRuntimeHints().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);
}
}

View File

@@ -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.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 WebFluxEndpointHandlerMapping}.
*
* @author Moritz Halbritter
*/
class WebFluxEndpointHandlerMappingTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new WebFluxEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onMethod(WebFluxLinksHandler.class, "links"))
.accepts(runtimeHints);
assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
}
}

View File

@@ -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.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 AbstractWebMvcEndpointHandlerMapping}.
*
* @author Moritz Halbritter
*/
class AbstractWebMvcEndpointHandlerMappingTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new AbstractWebMvcEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of(
"org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler")))
.accepts(runtimeHints);
}
}

View File

@@ -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.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 WebMvcEndpointHandlerMapping}.
*
* @author Moritz Halbritter
*/
class WebMvcEndpointHandlerMappingTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new WebMvcEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onMethod(WebMvcLinksHandler.class, "links"))
.accepts(runtimeHints);
assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
}
}

View File

@@ -19,14 +19,19 @@ package org.springframework.boot.actuate.health;
import java.time.Duration;
import java.util.Collections;
import java.util.Map;
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.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;
import org.springframework.boot.actuate.health.HealthEndpointWebExtension.HealthEndpointWebExtensionRuntimeHints;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -36,6 +41,7 @@ import static org.mockito.Mockito.mock;
*
* @author Phillip Webb
* @author Scott Frederick
* @author Moritz Halbritter
*/
class HealthEndpointWebExtensionTests extends
HealthEndpointSupportTests<HealthEndpointWebExtension, HealthContributorRegistry, HealthContributor, HealthComponent> {
@@ -81,6 +87,18 @@ class HealthEndpointWebExtensionTests extends
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new HealthEndpointWebExtensionRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
Set<Class<?>> 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);
}
}
@Override
protected HealthEndpointWebExtension create(HealthContributorRegistry registry, HealthEndpointGroups groups,
Duration slowIndicatorLoggingThreshold) {

View File

@@ -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.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 BuildInfoContributor}.
*
* @author Moritz Halbritter
*/
class BuildInfoContributorTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new BuildInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(BuildProperties.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -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,10 @@ import java.util.Properties;
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.actuate.info.InfoPropertiesInfoContributor.Mode;
import org.springframework.boot.info.GitProperties;
@@ -31,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link GitInfoContributor}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class GitInfoContributorTests {
@@ -79,4 +84,14 @@ class GitInfoContributorTests {
assertThat(id.get("abbrev")).isEqualTo("1b3cec3");
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new GitInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(GitProperties.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -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,6 +18,10 @@ 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;
@@ -26,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link JavaInfoContributor}
*
* @author Jonatan Ivanov
* @author Moritz Halbritter
*/
class JavaInfoContributorTests {
@@ -38,4 +43,13 @@ class JavaInfoContributorTests {
assertThat(info.getDetails().get("java")).isInstanceOf(JavaInfo.class);
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new JavaInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(JavaInfo.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -18,6 +18,10 @@ 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;
@@ -26,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link OsInfoContributor}
*
* @author Jonatan Ivanov
* @author Moritz Halbritter
*/
class OsInfoContributorTests {
@@ -38,4 +43,13 @@ class OsInfoContributorTests {
assertThat(info.getDetails().get("os")).isInstanceOf(OsInfo.class);
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new OsInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(OsInfo.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -16,10 +16,31 @@
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.IntegrationGraphServer;
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;
import static org.mockito.BDDMockito.given;
@@ -30,6 +51,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link IntegrationGraphEndpoint}.
*
* @author Tim Ysewyn
* @author Moritz Halbritter
*/
class IntegrationGraphEndpointTests {
@@ -52,4 +74,21 @@ class IntegrationGraphEndpointTests {
then(this.server).should().rebuild();
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new IntegrationGraphEndpointRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
Set<Class<?>> 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);
}
}
}

View File

@@ -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 extension;
private ThreadDumpEndpoint delegateMock;
@BeforeEach
void setUp() {
this.delegateMock = Mockito.mock(ThreadDumpEndpoint.class);
this.extension = new ThreadDumpEndpointWebExtension(this.delegateMock);
}
@Test
void shouldHandleThreadDumperUnavailable() {
Mockito.when(this.delegateMock.threadDump())
.thenThrow(new ThreadDumperUnavailableException("No thread dumper available"));
WebEndpointResponse<ThreadDumpDescriptor> response = this.extension.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<String> response = this.extension.textThreadDump();
assertThat(response.getStatus()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value());
}
}

View File

@@ -24,6 +24,10 @@ import io.micrometer.core.instrument.binder.MeterBinder;
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;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@@ -32,6 +36,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link HazelcastCacheMeterBinderProvider}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class HazelcastCacheMeterBinderProviderTests {
@@ -46,4 +51,13 @@ class HazelcastCacheMeterBinderProviderTests {
assertThat(meterBinder).isInstanceOf(HazelcastCacheMetrics.class);
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new HazelcastCacheMeterBinderProviderRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onMethod(HazelcastCache.class, "getNativeCache"))
.accepts(runtimeHints);
assertThat(RuntimeHintsPredicates.reflection().onType(HazelcastCacheMetrics.class)).accepts(runtimeHints);
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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 QuartzEndpointWebExtension}.
*
* @author Moritz Halbritter
*/
class QuartzEndpointWebExtensionTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new QuartzEndpointWebExtensionRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
Set<Class<?>> 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);
}
}
}

View File

@@ -19,14 +19,19 @@ package org.springframework.boot.actuate.scheduling;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Set;
import java.util.function.Consumer;
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 org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksReport;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
@@ -46,6 +51,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link ScheduledTasksEndpoint}.
*
* @author Andy Wilkinson
* @author Moritz Halbritter
*/
class ScheduledTasksEndpointTests {
@@ -149,6 +155,19 @@ class ScheduledTasksEndpointTests {
});
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new ScheduledTasksEndpointRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
Set<Class<?>> 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);
}
}
private void run(Class<?> configuration, Consumer<ScheduledTasksReport> consumer) {
this.contextRunner.withUserConfiguration(configuration)
.run((context) -> consumer.accept(context.getBean(ScheduledTasksEndpoint.class).scheduledTasks()));

View File

@@ -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,11 +16,17 @@
package org.springframework.boot.actuate.startup;
import java.util.Set;
import java.util.function.Consumer;
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.SpringBootVersion;
import org.springframework.boot.actuate.startup.StartupEndpoint.StartupEndpointRuntimeHints;
import org.springframework.boot.actuate.startup.StartupEndpoint.StartupResponse;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -35,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Brian Clozel
* @author Chris Bono
* @author Moritz Halbritter
*/
class StartupEndpointTests {
@@ -69,6 +76,19 @@ class StartupEndpointTests {
});
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new StartupEndpointRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
Set<TypeReference> 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);
}
}
private void testStartupEndpoint(ApplicationStartup applicationStartup, Consumer<StartupEndpoint> startupEndpoint) {
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withInitializer((context) -> context.setApplicationStartup(applicationStartup))

View File

@@ -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.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 DispatcherHandlersMappingDescriptionProvider}.
*
* @author Moritz Halbritter
*/
class DispatcherHandlersMappingDescriptionProviderTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new DispatcherHandlersMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints,
getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(DispatcherHandlerMappingDescription.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -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.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 DispatcherServletsMappingDescriptionProvider}.
*
* @author Moritz Halbritter
*/
class DispatcherServletsMappingDescriptionProviderTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new DispatcherServletsMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints,
getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(DispatcherServletMappingDescription.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -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.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 FiltersMappingDescriptionProvider}.
*
* @author Moritz Halbritter
*/
class FiltersMappingDescriptionProviderTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new FiltersMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(FilterRegistrationMappingDescription.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -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.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 ServletsMappingDescriptionProvider}.
*
* @author Moritz Halbritter
*/
class ServletsMappingDescriptionProviderTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new ServletsMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(ServletRegistrationMappingDescription.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@@ -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");
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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.
@@ -23,12 +23,16 @@ import java.util.Properties;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link BuildProperties}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class BuildPropertiesTests {
@@ -53,6 +57,14 @@ class BuildPropertiesTests {
assertThat(properties.getTime()).isNull();
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new BuildProperties.BuildPropertiesRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.resource().forResource("META-INF/build-info.properties"))
.accepts(runtimeHints);
}
private static Properties createProperties(String group, String artifact, String version, String buildTime) {
Properties properties = new Properties();
properties.put("group", group);

View File

@@ -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.
@@ -20,12 +20,16 @@ import java.util.Properties;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link GitProperties}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class GitPropertiesTests {
@@ -94,6 +98,13 @@ class GitPropertiesTests {
assertThat(properties.getShortCommitId()).isEqualTo("abcdefg");
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new GitProperties.GitPropertiesRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.resource().forResource("git.properties")).accepts(runtimeHints);
}
private static Properties createProperties(String branch, String commitId, String commitIdAbbrev,
String commitTime) {
Properties properties = new Properties();