Skip to content

Commit 584b7d1

Browse files
mhalbrittersnicoll
authored andcommitted
Add AOT support for actuator
Mainly adds reflection hints for the actuator infrastructure. Also adds the OperationReflectiveProcessor, which registers the @ReadMethod, @DeleteMethod and @WriteMethod annotated methods for reflection and adds reflection hints for method return types. See gh-31671
1 parent 00ec17b commit 584b7d1

File tree

70 files changed

+2413
-30
lines changed

Some content is hidden

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

70 files changed

+2413
-30
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: 25 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.
@@ -19,14 +19,20 @@
1919
import java.util.Collection;
2020
import java.util.Collections;
2121
import java.util.LinkedHashMap;
22+
import java.util.List;
2223
import java.util.Map;
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.ExecutableMode;
30+
import org.springframework.aot.hint.RuntimeHints;
31+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
32+
import org.springframework.aot.hint.TypeReference;
2833
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
2934
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse;
35+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints;
3036
import org.springframework.boot.actuate.endpoint.EndpointId;
3137
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
3238
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
@@ -35,6 +41,8 @@
3541
import org.springframework.boot.actuate.endpoint.web.Link;
3642
import org.springframework.boot.actuate.endpoint.web.WebOperation;
3743
import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping;
44+
import org.springframework.context.annotation.ImportRuntimeHints;
45+
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
3846
import org.springframework.http.HttpStatus;
3947
import org.springframework.http.ResponseEntity;
4048
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -50,6 +58,7 @@
5058
* @author Phillip Webb
5159
* @author Brian Clozel
5260
*/
61+
@ImportRuntimeHints(CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints.class)
5362
class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping {
5463

5564
private final CloudFoundrySecurityInterceptor securityInterceptor;
@@ -145,4 +154,19 @@ private Mono<ResponseEntity<Object>> flatMapResponse(ServerWebExchange exchange,
145154

146155
}
147156

157+
static class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
158+
159+
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
160+
161+
@Override
162+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
163+
hints.reflection().registerType(CloudFoundryLinksHandler.class,
164+
(hint) -> hint.onReachableType(TypeReference.of(CloudFoundryLinksHandler.class)).withMethod("links",
165+
List.of(TypeReference.of(ServerWebExchange.class)),
166+
(method) -> method.setModes(ExecutableMode.INVOKE)));
167+
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
168+
}
169+
170+
}
171+
148172
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Collection;
2020
import java.util.Collections;
2121
import java.util.LinkedHashMap;
22+
import java.util.List;
2223
import java.util.Map;
2324
import java.util.stream.Collectors;
2425

@@ -27,8 +28,13 @@
2728
import org.apache.commons.logging.Log;
2829
import org.apache.commons.logging.LogFactory;
2930

31+
import org.springframework.aot.hint.ExecutableMode;
32+
import org.springframework.aot.hint.RuntimeHints;
33+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
34+
import org.springframework.aot.hint.TypeReference;
3035
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
3136
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse;
37+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints;
3238
import org.springframework.boot.actuate.endpoint.EndpointId;
3339
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
3440
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
@@ -37,6 +43,8 @@
3743
import org.springframework.boot.actuate.endpoint.web.Link;
3844
import org.springframework.boot.actuate.endpoint.web.WebOperation;
3945
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
46+
import org.springframework.context.annotation.ImportRuntimeHints;
47+
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
4048
import org.springframework.http.HttpStatus;
4149
import org.springframework.http.ResponseEntity;
4250
import org.springframework.web.bind.annotation.ResponseBody;
@@ -51,6 +59,7 @@
5159
* @author Phillip Webb
5260
* @author Brian Clozel
5361
*/
62+
@ImportRuntimeHints(CloudFoundryWebEndpointServletHandlerMappingRuntimeHints.class)
5463
class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {
5564

5665
private static final Log logger = LogFactory.getLog(CloudFoundryWebEndpointServletHandlerMapping.class);
@@ -147,4 +156,20 @@ public Object handle(HttpServletRequest request, Map<String, String> body) {
147156

148157
}
149158

159+
static class CloudFoundryWebEndpointServletHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
160+
161+
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
162+
163+
@Override
164+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
165+
hints.reflection().registerType(CloudFoundryLinksHandler.class,
166+
(hint) -> hint.onReachableType(TypeReference.of(CloudFoundryLinksHandler.class)).withMethod("links",
167+
List.of(TypeReference.of(HttpServletRequest.class),
168+
TypeReference.of(HttpServletResponse.class)),
169+
(method) -> method.setModes(ExecutableMode.INVOKE)));
170+
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
171+
}
172+
173+
}
174+
150175
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.stream.Collectors;
2121

2222
import org.springframework.beans.factory.ObjectProvider;
23+
import org.springframework.boot.actuate.aot.ActuatorAnnotationsRuntimeHintsRegistrar;
2324
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
2425
import org.springframework.boot.actuate.endpoint.annotation.EndpointConverter;
2526
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
@@ -30,6 +31,7 @@
3031
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3132
import org.springframework.boot.convert.ApplicationConversionService;
3233
import org.springframework.context.annotation.Bean;
34+
import org.springframework.context.annotation.ImportRuntimeHints;
3335
import org.springframework.core.convert.ConversionService;
3436
import org.springframework.core.convert.converter.Converter;
3537
import org.springframework.core.convert.converter.GenericConverter;
@@ -45,6 +47,7 @@
4547
* @since 2.0.0
4648
*/
4749
@AutoConfiguration
50+
@ImportRuntimeHints(ActuatorAnnotationsRuntimeHintsRegistrar.class)
4851
public class EndpointAutoConfiguration {
4952

5053
@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
}
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;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.aot.hint.MemberCategory;
22+
import org.springframework.aot.hint.RuntimeHints;
23+
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
24+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
/**
29+
* Tests for {@link CloudFoundryWebEndpointDiscovererRuntimeHints}.
30+
*
31+
* @author Moritz Halbritter
32+
*/
33+
class CloudFoundryWebEndpointDiscovererRuntimeHintsTests {
34+
35+
private final CloudFoundryWebEndpointDiscovererRuntimeHints sut = new CloudFoundryWebEndpointDiscovererRuntimeHints();
36+
37+
@Test
38+
void shouldRegisterHints() {
39+
RuntimeHints runtimeHints = new RuntimeHints();
40+
this.sut.registerHints(runtimeHints, getClass().getClassLoader());
41+
assertThat(RuntimeHintsPredicates.reflection().onType(CloudFoundryEndpointFilter.class)
42+
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).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.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 CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints}.
30+
*
31+
* @author Moritz Halbritter
32+
*/
33+
class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHintsTests {
34+
35+
private final CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints sut = new CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints();
36+
37+
@Test
38+
void shouldRegisterHints() {
39+
RuntimeHints runtimeHints = new RuntimeHints();
40+
this.sut.registerHints(runtimeHints, getClass().getClassLoader());
41+
Assertions.assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links"))
42+
.accepts(runtimeHints);
43+
Assertions.assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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 CloudFoundryWebEndpointServletHandlerMappingRuntimeHints}.
31+
*
32+
* @author Moritz Halbritter
33+
*/
34+
class CloudFoundryWebEndpointServletHandlerMappingRuntimeHintsTests {
35+
36+
private final CloudFoundryWebEndpointServletHandlerMappingRuntimeHints sut = new CloudFoundryWebEndpointServletHandlerMappingRuntimeHints();
37+
38+
@Test
39+
void shouldRegisterHints() {
40+
RuntimeHints runtimeHints = new RuntimeHints();
41+
this.sut.registerHints(runtimeHints, getClass().getClassLoader());
42+
assertThat(RuntimeHintsPredicates.reflection().onMethod(CloudFoundryLinksHandler.class, "links"))
43+
.accepts(runtimeHints);
44+
assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
45+
}
46+
47+
}

0 commit comments

Comments
 (0)