Skip to content

Commit 6ff338b

Browse files
committed
Merge pull request #31671 from mhalbritter
* pr/31671: Polish "Add AOT support for actuator" Add AOT support for actuator Closes gh-31671
2 parents 00ec17b + 51cba6e commit 6ff338b

File tree

69 files changed

+1869
-38
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1869
-38
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscoverer.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,10 @@
1919
import java.util.Collection;
2020
import java.util.List;
2121

22+
import org.springframework.aot.hint.MemberCategory;
23+
import org.springframework.aot.hint.RuntimeHints;
24+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
25+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints;
2226
import org.springframework.boot.actuate.endpoint.EndpointFilter;
2327
import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;
2428
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
@@ -29,6 +33,7 @@
2933
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
3034
import org.springframework.boot.actuate.health.HealthEndpoint;
3135
import org.springframework.context.ApplicationContext;
36+
import org.springframework.context.annotation.ImportRuntimeHints;
3237
import org.springframework.core.annotation.MergedAnnotations;
3338

3439
/**
@@ -38,6 +43,7 @@
3843
* @author Madhura Bhave
3944
* @since 2.0.0
4045
*/
46+
@ImportRuntimeHints(CloudFoundryWebEndpointDiscovererRuntimeHints.class)
4147
public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
4248

4349
/**
@@ -75,4 +81,14 @@ private boolean isCloudFoundryHealthEndpointExtension(Class<?> extensionBeanType
7581
return MergedAnnotations.from(extensionBeanType).isPresent(EndpointCloudFoundryExtension.class);
7682
}
7783

84+
static class CloudFoundryWebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {
85+
86+
@Override
87+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
88+
hints.reflection().registerType(CloudFoundryEndpointFilter.class,
89+
(hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
90+
}
91+
92+
}
93+
7894
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,13 +20,17 @@
2020
import java.util.Collections;
2121
import java.util.LinkedHashMap;
2222
import java.util.Map;
23+
import java.util.Objects;
2324
import java.util.stream.Collectors;
2425

2526
import org.reactivestreams.Publisher;
2627
import reactor.core.publisher.Mono;
2728

29+
import org.springframework.aot.hint.RuntimeHints;
30+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
2831
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
2932
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse;
33+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints;
3034
import org.springframework.boot.actuate.endpoint.EndpointId;
3135
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
3236
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
@@ -35,9 +39,12 @@
3539
import org.springframework.boot.actuate.endpoint.web.Link;
3640
import org.springframework.boot.actuate.endpoint.web.WebOperation;
3741
import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping;
42+
import org.springframework.context.annotation.ImportRuntimeHints;
43+
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
3844
import org.springframework.http.HttpStatus;
3945
import org.springframework.http.ResponseEntity;
4046
import org.springframework.http.server.reactive.ServerHttpRequest;
47+
import org.springframework.util.ReflectionUtils;
4148
import org.springframework.web.cors.CorsConfiguration;
4249
import org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;
4350
import org.springframework.web.server.ServerWebExchange;
@@ -50,6 +57,7 @@
5057
* @author Phillip Webb
5158
* @author Brian Clozel
5259
*/
60+
@ImportRuntimeHints(CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints.class)
5361
class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping {
5462

5563
private final CloudFoundrySecurityInterceptor securityInterceptor;
@@ -145,4 +153,17 @@ private Mono<ResponseEntity<Object>> flatMapResponse(ServerWebExchange exchange,
145153

146154
}
147155

156+
static class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
157+
158+
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
159+
160+
@Override
161+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
162+
hints.reflection().registerMethod(Objects.requireNonNull(
163+
ReflectionUtils.findMethod(CloudFoundryLinksHandler.class, "links", ServerWebExchange.class)));
164+
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
165+
}
166+
167+
}
168+
148169
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@
2020
import java.util.Collections;
2121
import java.util.LinkedHashMap;
2222
import java.util.Map;
23+
import java.util.Objects;
2324
import java.util.stream.Collectors;
2425

2526
import jakarta.servlet.http.HttpServletRequest;
2627
import jakarta.servlet.http.HttpServletResponse;
2728
import org.apache.commons.logging.Log;
2829
import org.apache.commons.logging.LogFactory;
2930

31+
import org.springframework.aot.hint.RuntimeHints;
32+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
3033
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
3134
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse;
35+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints;
3236
import org.springframework.boot.actuate.endpoint.EndpointId;
3337
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
3438
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
@@ -37,8 +41,11 @@
3741
import org.springframework.boot.actuate.endpoint.web.Link;
3842
import org.springframework.boot.actuate.endpoint.web.WebOperation;
3943
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
44+
import org.springframework.context.annotation.ImportRuntimeHints;
45+
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
4046
import org.springframework.http.HttpStatus;
4147
import org.springframework.http.ResponseEntity;
48+
import org.springframework.util.ReflectionUtils;
4249
import org.springframework.web.bind.annotation.ResponseBody;
4350
import org.springframework.web.cors.CorsConfiguration;
4451
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
@@ -51,6 +58,7 @@
5158
* @author Phillip Webb
5259
* @author Brian Clozel
5360
*/
61+
@ImportRuntimeHints(CloudFoundryWebEndpointServletHandlerMappingRuntimeHints.class)
5462
class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {
5563

5664
private static final Log logger = LogFactory.getLog(CloudFoundryWebEndpointServletHandlerMapping.class);
@@ -147,4 +155,18 @@ public Object handle(HttpServletRequest request, Map<String, String> body) {
147155

148156
}
149157

158+
static class CloudFoundryWebEndpointServletHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
159+
160+
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
161+
162+
@Override
163+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
164+
hints.reflection()
165+
.registerMethod(Objects.requireNonNull(ReflectionUtils.findMethod(CloudFoundryLinksHandler.class,
166+
"links", HttpServletRequest.class, HttpServletResponse.class)));
167+
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
168+
}
169+
170+
}
171+
150172
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.endpoint;
18+
19+
import java.util.stream.Stream;
20+
21+
import org.springframework.aot.hint.RuntimeHints;
22+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
23+
import org.springframework.aot.hint.support.RuntimeHintsUtils;
24+
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
25+
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
26+
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
27+
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
28+
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
29+
import org.springframework.core.annotation.SynthesizedAnnotation;
30+
31+
/**
32+
* {@link RuntimeHintsRegistrar} for actuator support.
33+
*
34+
* @author Moritz Halbritter
35+
*/
36+
class ActuatorAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
37+
38+
@Override
39+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
40+
Stream.of(Endpoint.class, ReadOperation.class, WriteOperation.class, DeleteOperation.class,
41+
EndpointExtension.class)
42+
.forEach((annotationType) -> RuntimeHintsUtils.registerAnnotation(hints, annotationType));
43+
// TODO: See https://github.com/spring-projects/spring-framework/issues/28767
44+
Stream.of(Endpoint.class, EndpointExtension.class).forEach(
45+
(annotationType) -> hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class));
46+
}
47+
48+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3131
import org.springframework.boot.convert.ApplicationConversionService;
3232
import org.springframework.context.annotation.Bean;
33+
import org.springframework.context.annotation.ImportRuntimeHints;
3334
import org.springframework.core.convert.ConversionService;
3435
import org.springframework.core.convert.converter.Converter;
3536
import org.springframework.core.convert.converter.GenericConverter;
@@ -45,6 +46,7 @@
4546
* @since 2.0.0
4647
*/
4748
@AutoConfiguration
49+
@ImportRuntimeHints(ActuatorAnnotationsRuntimeHints.class)
4850
public class EndpointAutoConfiguration {
4951

5052
@Bean

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfiguration.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
package org.springframework.boot.actuate.autoconfigure.management;
1818

1919
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
20+
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
2021
import org.springframework.boot.actuate.management.ThreadDumpEndpoint;
22+
import org.springframework.boot.actuate.management.ThreadDumpEndpointWebExtension;
2123
import org.springframework.boot.autoconfigure.AutoConfiguration;
2224
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2326
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2427
import org.springframework.context.annotation.Bean;
2528

@@ -39,4 +42,12 @@ public ThreadDumpEndpoint dumpEndpoint() {
3942
return new ThreadDumpEndpoint();
4043
}
4144

45+
@Bean
46+
@ConditionalOnMissingBean
47+
@ConditionalOnBean(ThreadDumpEndpoint.class)
48+
@ConditionalOnAvailableEndpoint(exposure = { EndpointExposure.WEB, EndpointExposure.CLOUD_FOUNDRY })
49+
public ThreadDumpEndpointWebExtension threadDumpWebExtension(ThreadDumpEndpoint threadDumpEndpoint) {
50+
return new ThreadDumpEndpointWebExtension(threadDumpEndpoint);
51+
}
52+
4253
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
import org.junit.jupiter.api.Test;
2525

26+
import org.springframework.aot.hint.MemberCategory;
27+
import org.springframework.aot.hint.RuntimeHints;
28+
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
29+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints;
2630
import org.springframework.boot.actuate.endpoint.EndpointId;
2731
import org.springframework.boot.actuate.endpoint.InvocationContext;
2832
import org.springframework.boot.actuate.endpoint.SecurityContext;
@@ -50,6 +54,7 @@
5054
* Tests for {@link CloudFoundryWebEndpointDiscoverer}.
5155
*
5256
* @author Madhura Bhave
57+
* @author Moritz Halbritter
5358
*/
5459
class CloudFoundryWebEndpointDiscovererTests {
5560

@@ -69,6 +74,14 @@ void getEndpointsShouldAddCloudFoundryHealthExtension() {
6974
});
7075
}
7176

77+
@Test
78+
void shouldRegisterHints() {
79+
RuntimeHints runtimeHints = new RuntimeHints();
80+
new CloudFoundryWebEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
81+
assertThat(RuntimeHintsPredicates.reflection().onType(CloudFoundryEndpointFilter.class)
82+
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);
83+
}
84+
7285
private WebOperation findMainReadOperation(ExposableWebEndpoint endpoint) {
7386
for (WebOperation operation : endpoint.getOperations()) {
7487
if (operation.getRequestPredicate().getPath().equals("health")) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive;
18+
19+
import org.assertj.core.api.Assertions;
20+
import org.junit.jupiter.api.Test;
21+
22+
import org.springframework.aot.hint.RuntimeHints;
23+
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
24+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryLinksHandler;
25+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints;
26+
import org.springframework.boot.actuate.endpoint.web.Link;
27+
28+
/**
29+
* Tests for {@link CloudFoundryWebFluxEndpointHandlerMapping}.
30+
*
31+
* @author Moritz Halbritter
32+
*/
33+
class CloudFoundryWebFluxEndpointHandlerMappingTests {
34+
35+
@Test
36+
void shouldRegisterHints() {
37+
RuntimeHints runtimeHints = new RuntimeHints();
38+
new CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints,
39+
getClass().getClassLoader());
40+
Assertions.assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links"))
41+
.accepts(runtimeHints);
42+
Assertions.assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
43+
}
44+
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.aot.hint.RuntimeHints;
22+
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
23+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryLinksHandler;
24+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints;
25+
import org.springframework.boot.actuate.endpoint.web.Link;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* Tests for {@link CloudFoundryWebEndpointServletHandlerMapping}.
31+
*
32+
* @author Moritz Halbritter
33+
*/
34+
class CloudFoundryWebEndpointServletHandlerMappingTests {
35+
36+
@Test
37+
void shouldRegisterHints() {
38+
RuntimeHints runtimeHints = new RuntimeHints();
39+
new CloudFoundryWebEndpointServletHandlerMappingRuntimeHints().registerHints(runtimeHints,
40+
getClass().getClassLoader());
41+
assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links"))
42+
.accepts(runtimeHints);
43+
assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
44+
}
45+
46+
}

0 commit comments

Comments
 (0)