Skip to content

Commit 2a989b3

Browse files
committed
Create Environment and apply ConversionService to management contexts
Update `ManagementContextFactory` implementations to create an appropriate `Environment` type and to apply the `ConversionService` from the parent context. Prior to this commit, the management context `Environment` would not be able to convert values from a `configtree:` source due to a missing converter. Fixes gh-32941
1 parent 51a1673 commit 2a989b3

File tree

4 files changed

+94
-4
lines changed

4 files changed

+94
-4
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementContextFactory.java

Lines changed: 12 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.
@@ -23,12 +23,16 @@
2323
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2424
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2525
import org.springframework.beans.factory.support.RootBeanDefinition;
26+
import org.springframework.boot.ApplicationContextFactory;
27+
import org.springframework.boot.WebApplicationType;
2628
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextFactory;
2729
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration;
2830
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
2931
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
3032
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
3133
import org.springframework.context.ApplicationContext;
34+
import org.springframework.core.env.ConfigurableEnvironment;
35+
import org.springframework.core.env.Environment;
3236
import org.springframework.util.ObjectUtils;
3337

3438
/**
@@ -41,7 +45,14 @@ class ReactiveManagementContextFactory implements ManagementContextFactory {
4145
@Override
4246
public ConfigurableWebServerApplicationContext createManagementContext(ApplicationContext parent,
4347
Class<?>... configClasses) {
48+
Environment parentEnvironment = parent.getEnvironment();
49+
ConfigurableEnvironment childEnvironment = ApplicationContextFactory.DEFAULT
50+
.createEnvironment(WebApplicationType.REACTIVE);
51+
if (parentEnvironment instanceof ConfigurableEnvironment) {
52+
childEnvironment.setConversionService(((ConfigurableEnvironment) parentEnvironment).getConversionService());
53+
}
4454
AnnotationConfigReactiveWebServerApplicationContext child = new AnnotationConfigReactiveWebServerApplicationContext();
55+
child.setEnvironment(childEnvironment);
4556
child.setParent(parent);
4657
Class<?>[] combinedClasses = ObjectUtils.addObjectToArray(configClasses,
4758
ReactiveWebServerFactoryAutoConfiguration.class);

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/ServletManagementContextFactory.java

Lines changed: 12 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.
@@ -26,12 +26,16 @@
2626
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2727
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2828
import org.springframework.beans.factory.support.RootBeanDefinition;
29+
import org.springframework.boot.ApplicationContextFactory;
30+
import org.springframework.boot.WebApplicationType;
2931
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextFactory;
3032
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
3133
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
3234
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
3335
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
3436
import org.springframework.context.ApplicationContext;
37+
import org.springframework.core.env.ConfigurableEnvironment;
38+
import org.springframework.core.env.Environment;
3539
import org.springframework.util.ClassUtils;
3640

3741
/**
@@ -44,7 +48,14 @@ class ServletManagementContextFactory implements ManagementContextFactory {
4448
@Override
4549
public ConfigurableWebServerApplicationContext createManagementContext(ApplicationContext parent,
4650
Class<?>... configClasses) {
51+
Environment parentEnvironment = parent.getEnvironment();
52+
ConfigurableEnvironment childEnvironment = ApplicationContextFactory.DEFAULT
53+
.createEnvironment(WebApplicationType.SERVLET);
54+
if (parentEnvironment instanceof ConfigurableEnvironment) {
55+
childEnvironment.setConversionService(((ConfigurableEnvironment) parentEnvironment).getConversionService());
56+
}
4757
AnnotationConfigServletWebServerApplicationContext child = new AnnotationConfigServletWebServerApplicationContext();
58+
child.setEnvironment(childEnvironment);
4859
child.setParent(parent);
4960
List<Class<?>> combinedClasses = new ArrayList<>(Arrays.asList(configClasses));
5061
combinedClasses.add(ServletWebServerFactoryAutoConfiguration.class);

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfigurationIntegrationTests.java

Lines changed: 35 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.
@@ -16,9 +16,13 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.web.reactive;
1818

19+
import java.io.IOException;
20+
import java.nio.charset.StandardCharsets;
21+
import java.nio.file.Path;
1922
import java.util.function.Consumer;
2023

2124
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.io.TempDir;
2226

2327
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
2428
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
@@ -29,12 +33,17 @@
2933
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
3034
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration;
3135
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
36+
import org.springframework.boot.convert.ApplicationConversionService;
37+
import org.springframework.boot.env.ConfigTreePropertySource;
3238
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
3339
import org.springframework.boot.test.context.runner.ContextConsumer;
3440
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
3541
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
3642
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
43+
import org.springframework.context.ConfigurableApplicationContext;
44+
import org.springframework.core.convert.support.ConfigurableConversionService;
3745
import org.springframework.http.MediaType;
46+
import org.springframework.util.FileCopyUtils;
3847
import org.springframework.web.reactive.function.client.WebClient;
3948

4049
import static org.assertj.core.api.Assertions.assertThat;
@@ -57,6 +66,9 @@ class ReactiveManagementChildContextConfigurationIntegrationTests {
5766
.withInitializer(new ServerPortInfoApplicationContextInitializer()).withPropertyValues(
5867
"server.port=0", "management.server.port=0", "management.endpoints.web.exposure.include=*");
5968

69+
@TempDir
70+
Path temp;
71+
6072
@Test
6173
void endpointsAreBeneathActuatorByDefault() {
6274
this.runner.withPropertyValues("management.server.port:0").run(withWebTestClient((client) -> {
@@ -76,6 +88,28 @@ void whenManagementServerBasePathIsConfiguredThenEndpointsAreBeneathThatPath() {
7688
}));
7789
}
7890

91+
@Test // gh-32941
92+
void whenManagementServerPortLoadedFromConfigTree() {
93+
this.runner.withInitializer(this::addConfigTreePropertySource)
94+
.run((context) -> assertThat(context).hasNotFailed());
95+
}
96+
97+
private void addConfigTreePropertySource(ConfigurableApplicationContext applicationContext) {
98+
try {
99+
applicationContext.getEnvironment().setConversionService(
100+
(ConfigurableConversionService) ApplicationConversionService.getSharedInstance());
101+
Path configtree = this.temp.resolve("configtree");
102+
Path file = configtree.resolve("management/server/port");
103+
file.toFile().getParentFile().mkdirs();
104+
FileCopyUtils.copy("0".getBytes(StandardCharsets.UTF_8), file.toFile());
105+
ConfigTreePropertySource source = new ConfigTreePropertySource("configtree", configtree);
106+
applicationContext.getEnvironment().getPropertySources().addFirst(source);
107+
}
108+
catch (IOException ex) {
109+
throw new IllegalStateException(ex);
110+
}
111+
}
112+
79113
private ContextConsumer<AssertableReactiveWebApplicationContext> withWebTestClient(Consumer<WebClient> webClient) {
80114
return (context) -> {
81115
String port = context.getEnvironment().getProperty("local.management.port");

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/WebMvcEndpointChildContextConfigurationIntegrationTests.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 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.
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.web.servlet;
1818

19+
import java.io.IOException;
20+
import java.nio.charset.StandardCharsets;
21+
import java.nio.file.Path;
1922
import java.util.Collections;
2023
import java.util.Map;
2124
import java.util.function.Consumer;
@@ -25,6 +28,7 @@
2528
import javax.validation.constraints.NotEmpty;
2629

2730
import org.junit.jupiter.api.Test;
31+
import org.junit.jupiter.api.io.TempDir;
2832
import reactor.core.publisher.Mono;
2933

3034
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
@@ -37,13 +41,18 @@
3741
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
3842
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
3943
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
44+
import org.springframework.boot.convert.ApplicationConversionService;
45+
import org.springframework.boot.env.ConfigTreePropertySource;
4046
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
4147
import org.springframework.boot.test.context.runner.ContextConsumer;
4248
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
4349
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
4450
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
51+
import org.springframework.context.ConfigurableApplicationContext;
4552
import org.springframework.core.ParameterizedTypeReference;
53+
import org.springframework.core.convert.support.ConfigurableConversionService;
4654
import org.springframework.http.MediaType;
55+
import org.springframework.util.FileCopyUtils;
4756
import org.springframework.web.bind.annotation.GetMapping;
4857
import org.springframework.web.bind.annotation.PostMapping;
4958
import org.springframework.web.bind.annotation.RequestBody;
@@ -75,6 +84,9 @@ class WebMvcEndpointChildContextConfigurationIntegrationTests {
7584
"management.endpoints.web.exposure.include=*", "server.error.include-exception=true",
7685
"server.error.include-message=always", "server.error.include-binding-errors=always");
7786

87+
@TempDir
88+
Path temp;
89+
7890
@Test // gh-17938
7991
void errorEndpointIsUsedWithEndpoint() {
8092
this.runner.run(withWebTestClient((client) -> {
@@ -135,6 +147,28 @@ void whenManagementServerBasePathIsConfiguredThenEndpointsAreBeneathThatPath() {
135147
}));
136148
}
137149

150+
@Test // gh-32941
151+
void whenManagementServerPortLoadedFromConfigTree() {
152+
this.runner.withInitializer(this::addConfigTreePropertySource)
153+
.run((context) -> assertThat(context).hasNotFailed());
154+
}
155+
156+
private void addConfigTreePropertySource(ConfigurableApplicationContext applicationContext) {
157+
try {
158+
applicationContext.getEnvironment().setConversionService(
159+
(ConfigurableConversionService) ApplicationConversionService.getSharedInstance());
160+
Path configtree = this.temp.resolve("configtree");
161+
Path file = configtree.resolve("management/server/port");
162+
file.toFile().getParentFile().mkdirs();
163+
FileCopyUtils.copy("0".getBytes(StandardCharsets.UTF_8), file.toFile());
164+
ConfigTreePropertySource source = new ConfigTreePropertySource("configtree", configtree);
165+
applicationContext.getEnvironment().getPropertySources().addFirst(source);
166+
}
167+
catch (IOException ex) {
168+
throw new IllegalStateException(ex);
169+
}
170+
}
171+
138172
private ContextConsumer<AssertableWebApplicationContext> withWebTestClient(Consumer<WebClient> webClient) {
139173
return (context) -> {
140174
String port = context.getEnvironment().getProperty("local.management.port");

0 commit comments

Comments
 (0)