Skip to content

Commit bd4fa3c

Browse files
committed
Add additional profiles to ConfigFileApplicationListener
Add additional profiles which are set by programmatically, to Spring's environment property sources when legacy processing is used This commit updates the following areas: - Add additionalProfiles field to ConfigFileApplicationListener to pass SpringApplication's addition profiles which are set by programmatically, to ConfigFileApplicationListener from ConfigDataEnvironmentPostProcessor - Add additional profiles into Spring's environment property sources - Supplement unit test for SpringApplicationTests Closes #25704
1 parent 269fc68 commit bd4fa3c

File tree

6 files changed

+113
-39
lines changed

6 files changed

+113
-39
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessor.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
*
4242
* @author Phillip Webb
4343
* @author Madhura Bhave
44+
* @author Nguyen Bao Sach
4445
* @since 2.4.0
4546
*/
4647
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
@@ -99,7 +100,7 @@ void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader
99100
catch (UseLegacyConfigProcessingException ex) {
100101
this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]",
101102
ex.getConfigurationProperty()));
102-
postProcessUsingLegacyApplicationListener(environment, resourceLoader);
103+
postProcessUsingLegacyApplicationListener(environment, resourceLoader, additionalProfiles);
103104
}
104105
}
105106

@@ -110,13 +111,14 @@ ConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environme
110111
}
111112

112113
private void postProcessUsingLegacyApplicationListener(ConfigurableEnvironment environment,
113-
ResourceLoader resourceLoader) {
114-
getLegacyListener().addPropertySources(environment, resourceLoader);
114+
ResourceLoader resourceLoader, Collection<String> additionalProfiles) {
115+
getLegacyListener(additionalProfiles).addPropertySources(environment, resourceLoader);
115116
}
116117

117118
@SuppressWarnings("deprecation")
118-
LegacyConfigFileApplicationListener getLegacyListener() {
119-
return new LegacyConfigFileApplicationListener(this.logFactory.getLog(ConfigFileApplicationListener.class));
119+
LegacyConfigFileApplicationListener getLegacyListener(Collection<String> additionalProfiles) {
120+
return new LegacyConfigFileApplicationListener(this.logFactory.getLog(ConfigFileApplicationListener.class),
121+
additionalProfiles);
120122
}
121123

122124
/**
@@ -189,8 +191,8 @@ public static void applyTo(ConfigurableEnvironment environment, ResourceLoader r
189191
@SuppressWarnings("deprecation")
190192
static class LegacyConfigFileApplicationListener extends ConfigFileApplicationListener {
191193

192-
LegacyConfigFileApplicationListener(Log logger) {
193-
super(logger);
194+
LegacyConfigFileApplicationListener(Log logger, Collection<String> additionalProfiles) {
195+
super(logger, additionalProfiles);
194196
}
195197

196198
@Override

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,7 @@
2020
import java.io.IOException;
2121
import java.nio.file.Path;
2222
import java.nio.file.Paths;
23-
import java.util.ArrayList;
24-
import java.util.Arrays;
25-
import java.util.Collections;
26-
import java.util.Comparator;
27-
import java.util.Deque;
28-
import java.util.HashMap;
29-
import java.util.HashSet;
30-
import java.util.LinkedHashMap;
31-
import java.util.LinkedHashSet;
32-
import java.util.LinkedList;
33-
import java.util.List;
34-
import java.util.Map;
35-
import java.util.Objects;
36-
import java.util.Set;
23+
import java.util.*;
3724
import java.util.function.BiConsumer;
3825
import java.util.function.Function;
3926
import java.util.stream.Collectors;
@@ -111,6 +98,7 @@
11198
* @author Eddú Meléndez
11299
* @author Madhura Bhave
113100
* @author Scott Frederick
101+
* @author Nguyen Bao Sach
114102
* @since 1.0.0
115103
* @deprecated since 2.4.0 in favor of {@link ConfigDataEnvironmentPostProcessor}
116104
*/
@@ -179,6 +167,8 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
179167

180168
private int order = DEFAULT_ORDER;
181169

170+
private Collection<String> additionalProfiles = Collections.emptySet();
171+
182172
public ConfigFileApplicationListener() {
183173
this(new DeferredLog());
184174
}
@@ -187,6 +177,11 @@ public ConfigFileApplicationListener() {
187177
this.logger = logger;
188178
}
189179

180+
ConfigFileApplicationListener(Log logger, Collection<String> additionalProfiles) {
181+
this.logger = logger;
182+
this.additionalProfiles = additionalProfiles;
183+
}
184+
190185
@Override
191186
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
192187
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
@@ -353,11 +348,14 @@ private void initializeProfiles() {
353348
Binder binder = Binder.get(this.environment);
354349
Set<Profile> activatedViaProperty = getProfiles(binder, ACTIVE_PROFILES_PROPERTY);
355350
Set<Profile> includedViaProperty = getProfiles(binder, INCLUDE_PROFILES_PROPERTY);
356-
List<Profile> otherActiveProfiles = getOtherActiveProfiles(activatedViaProperty, includedViaProperty);
351+
Set<Profile> additionalProfiles = asProfileSet(
352+
ConfigFileApplicationListener.this.additionalProfiles.toArray(new String[0]));
353+
additionalProfiles.addAll(includedViaProperty);
354+
List<Profile> otherActiveProfiles = getOtherActiveProfiles(activatedViaProperty, additionalProfiles);
357355
this.profiles.addAll(otherActiveProfiles);
358356
// Any pre-existing active profiles set via property sources (e.g.
359357
// System properties) take precedence over those added in config files.
360-
this.profiles.addAll(includedViaProperty);
358+
this.profiles.addAll(additionalProfiles);
361359
addActiveProfiles(activatedViaProperty);
362360
if (this.profiles.size() == 1) { // only has null profile
363361
for (String defaultProfileName : this.environment.getDefaultProfiles()) {

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
* @author Brian Clozel
148148
* @author Artsiom Yudovin
149149
* @author Marten Deinum
150+
* @author Nguyen Bao Sach
150151
*/
151152
@ExtendWith(OutputCaptureExtension.class)
152153
class SpringApplicationTests {
@@ -604,6 +605,17 @@ void addProfilesOrder() {
604605
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
605606
}
606607

608+
@Test
609+
void includeProfilesOrder() {
610+
SpringApplication application = new SpringApplication(ExampleConfig.class);
611+
application.setWebApplicationType(WebApplicationType.NONE);
612+
ConfigurableEnvironment environment = new StandardEnvironment();
613+
application.setEnvironment(environment);
614+
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
615+
// Since Boot 2.4 included profiles should always be last
616+
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
617+
}
618+
607619
@Test
608620
void addProfilesOrderWithProperties() {
609621
SpringApplication application = new SpringApplication(ExampleConfig.class);

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
*
4949
* @author Phillip Webb
5050
* @author Madhura Bhave
51+
* @author Nguyen Bao Sach
5152
*/
5253
@ExtendWith(MockitoExtension.class)
5354
class ConfigDataEnvironmentPostProcessorTests {
@@ -111,10 +112,25 @@ void postProcessEnvironmentWhenUseLegacyProcessingSwitchesToLegacyMethod() {
111112
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener.class);
112113
willThrow(new UseLegacyConfigProcessingException(null)).given(this.postProcessor)
113114
.getConfigDataEnvironment(any(), any(), any());
114-
willReturn(legacyListener).given(this.postProcessor).getLegacyListener();
115+
willReturn(legacyListener).given(this.postProcessor).getLegacyListener(this.additionalProfilesCaptor.capture());
115116
this.postProcessor.postProcessEnvironment(this.environment, this.application);
116117
verifyNoInteractions(this.configDataEnvironment);
117118
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
119+
assertThat(this.additionalProfilesCaptor.getValue()).isEmpty();
120+
}
121+
122+
@Test
123+
void postProcessEnvironmentWhenHasAdditionalProfilesViaProgrammaticallySettingAndUseLegacyProcessing() {
124+
this.application.setAdditionalProfiles("dev");
125+
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener legacyListener = mock(
126+
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener.class);
127+
willThrow(new UseLegacyConfigProcessingException(null)).given(this.postProcessor)
128+
.getConfigDataEnvironment(any(), any(), any());
129+
willReturn(legacyListener).given(this.postProcessor).getLegacyListener(this.additionalProfilesCaptor.capture());
130+
this.postProcessor.postProcessEnvironment(this.environment, this.application);
131+
verifyNoInteractions(this.configDataEnvironment);
132+
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
133+
assertThat(this.additionalProfilesCaptor.getValue()).containsExactly("dev");
118134
}
119135

120136
@Test

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerLegacyReproTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
*
3434
* @author Phillip Webb
3535
* @author Dave Syer
36+
* @author Nguyen Bao Sach
3637
*/
3738
@ExtendWith(UseLegacyProcessing.class)
3839
class ConfigFileApplicationListenerLegacyReproTests {
@@ -167,6 +168,17 @@ void reverseOrderOfProfilesWithYamlAndNoOverride() {
167168
assertVersionProperty(this.context, "A", "C", "A");
168169
}
169170

171+
@Test
172+
void additionalProfilesViaProgrammaticallySetting() {
173+
// gh-25704
174+
SpringApplication application = new SpringApplication(Config.class);
175+
application.setWebApplicationType(WebApplicationType.NONE);
176+
application.setAdditionalProfiles("dev");
177+
this.context = application.run();
178+
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("dev"))).isTrue();
179+
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
180+
}
181+
170182
private void assertVersionProperty(ConfigurableApplicationContext context, String expectedVersion,
171183
String... expectedActiveProfiles) {
172184
assertThat(context.getEnvironment().getActiveProfiles()).isEqualTo(expectedActiveProfiles);

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,6 @@
1616

1717
package org.springframework.boot.context.config;
1818

19-
import java.io.File;
20-
import java.io.FileOutputStream;
21-
import java.io.OutputStream;
22-
import java.util.Collections;
23-
import java.util.HashMap;
24-
import java.util.List;
25-
import java.util.Map;
26-
import java.util.Properties;
27-
import java.util.stream.Collectors;
28-
import java.util.stream.StreamSupport;
29-
3019
import org.apache.commons.logging.Log;
3120
import org.apache.commons.logging.LogFactory;
3221
import org.apache.logging.log4j.Level;
@@ -46,11 +35,8 @@
4635
import org.springframework.context.annotation.Configuration;
4736
import org.springframework.context.annotation.Profile;
4837
import org.springframework.context.annotation.PropertySource;
49-
import org.springframework.core.env.ConfigurableEnvironment;
50-
import org.springframework.core.env.MapPropertySource;
5138
import org.springframework.core.env.Profiles;
52-
import org.springframework.core.env.SimpleCommandLinePropertySource;
53-
import org.springframework.core.env.StandardEnvironment;
39+
import org.springframework.core.env.*;
5440
import org.springframework.core.io.ByteArrayResource;
5541
import org.springframework.core.io.ClassPathResource;
5642
import org.springframework.core.io.Resource;
@@ -59,6 +45,13 @@
5945
import org.springframework.test.util.ReflectionTestUtils;
6046
import org.springframework.util.StringUtils;
6147

48+
import java.io.File;
49+
import java.io.FileOutputStream;
50+
import java.io.OutputStream;
51+
import java.util.*;
52+
import java.util.stream.Collectors;
53+
import java.util.stream.StreamSupport;
54+
6255
import static org.assertj.core.api.Assertions.assertThat;
6356
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
6457

@@ -70,6 +63,7 @@
7063
* @author Eddú Meléndez
7164
* @author Madhura Bhave
7265
* @author Scott Frederick
66+
* @author Nguyen Bao Sach
7367
*/
7468
@Deprecated
7569
@ExtendWith({ OutputCaptureExtension.class, UseLegacyProcessing.class })
@@ -1150,6 +1144,46 @@ void locationsWithWildcardFilesShouldIgnoreHiddenDirectories() {
11501144
assertThat(this.environment.getProperty("fourth.property")).isNull();
11511145
}
11521146

1147+
@Test
1148+
void additionalProfilesCanBeIncludedFromProgrammaticallySetting() {
1149+
// gh-25704
1150+
SpringApplication application = new SpringApplication(Config.class);
1151+
application.setWebApplicationType(WebApplicationType.NONE);
1152+
application.setAdditionalProfiles("dev");
1153+
this.context = application.run();
1154+
// Active profile should win over default
1155+
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
1156+
}
1157+
1158+
@Test
1159+
void twoAdditionalProfilesCanBeIncludedFromProgrammaticallySetting() {
1160+
// gh-25704
1161+
SpringApplication application = new SpringApplication(Config.class);
1162+
application.setWebApplicationType(WebApplicationType.NONE);
1163+
application.setAdditionalProfiles("other", "dev");
1164+
this.context = application.run();
1165+
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
1166+
}
1167+
1168+
@Test
1169+
void includeProfilesOrder() {
1170+
SpringApplication application = new SpringApplication(Config.class);
1171+
application.setWebApplicationType(WebApplicationType.NONE);
1172+
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
1173+
// Before Boot 2.4 included profiles should always be first
1174+
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
1175+
}
1176+
1177+
@Test
1178+
void addProfilesOrder() {
1179+
SpringApplication application = new SpringApplication(Config.class);
1180+
application.setWebApplicationType(WebApplicationType.NONE);
1181+
application.setAdditionalProfiles("foo");
1182+
this.context = application.run("--spring.profiles.active=bar,spam");
1183+
// Before Boot 2.4 additional profiles should always be first
1184+
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
1185+
}
1186+
11531187
private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {
11541188
return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) {
11551189

0 commit comments

Comments
 (0)