Skip to content

Commit d92c2f7

Browse files
committed
DefaultProperties profiles shouldn't take precedence over config files
Fixes gh-15445
1 parent 404f5d3 commit d92c2f7

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

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

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
5757
import org.springframework.core.env.ConfigurableEnvironment;
5858
import org.springframework.core.env.Environment;
59+
import org.springframework.core.env.MapPropertySource;
5960
import org.springframework.core.env.MutablePropertySources;
6061
import org.springframework.core.env.Profiles;
6162
import org.springframework.core.env.PropertySource;
@@ -323,6 +324,9 @@ public void load() {
323324
this.processedProfiles = new LinkedList<>();
324325
this.activatedProfiles = false;
325326
this.loaded = new LinkedHashMap<>();
327+
MapPropertySource defaultProperties = (MapPropertySource) this.environment
328+
.getPropertySources().get(DEFAULT_PROPERTIES);
329+
replaceDefaultPropertySourceIfNecessary(defaultProperties);
326330
initializeProfiles();
327331
while (!this.profiles.isEmpty()) {
328332
Profile profile = this.profiles.poll();
@@ -333,10 +337,19 @@ public void load() {
333337
addToLoaded(MutablePropertySources::addLast, false));
334338
this.processedProfiles.add(profile);
335339
}
336-
resetEnvironmentProfiles(this.processedProfiles);
337340
load(null, this::getNegativeProfileFilter,
338341
addToLoaded(MutablePropertySources::addFirst, true));
339342
addLoadedPropertySources();
343+
resetEnvironment(defaultProperties);
344+
}
345+
346+
private void replaceDefaultPropertySourceIfNecessary(
347+
MapPropertySource defaultProperties) {
348+
if (defaultProperties != null) {
349+
this.environment.getPropertySources().replace(DEFAULT_PROPERTIES,
350+
new FilteredDefaultPropertySource(DEFAULT_PROPERTIES,
351+
defaultProperties.getSource()));
352+
}
340353
}
341354

342355
/**
@@ -729,6 +742,76 @@ private void addLoadedPropertySource(MutablePropertySources destination,
729742
}
730743
}
731744

745+
private void resetEnvironment(MapPropertySource defaultProperties) {
746+
List<String> activeProfiles = new ArrayList<>();
747+
handleDefaultPropertySource(defaultProperties, activeProfiles);
748+
activeProfiles.addAll(this.processedProfiles.stream()
749+
.filter((profile) -> profile != null && !profile.isDefaultProfile())
750+
.map(Profile::getName).collect(Collectors.toList()));
751+
this.environment.setActiveProfiles(activeProfiles.toArray(new String[0]));
752+
}
753+
754+
private void handleDefaultPropertySource(MapPropertySource defaultProperties,
755+
List<String> activeProfiles) {
756+
if (defaultProperties != null) {
757+
Binder binder = new Binder(
758+
ConfigurationPropertySources.from(defaultProperties),
759+
new PropertySourcesPlaceholdersResolver(this.environment));
760+
List<String> includes = getDefaultProfiles(binder,
761+
"spring.profiles.include");
762+
activeProfiles.addAll(includes);
763+
if (!this.activatedProfiles) {
764+
List<String> active = getDefaultProfiles(binder,
765+
"spring.profiles.active");
766+
activeProfiles.addAll(active);
767+
}
768+
this.environment.getPropertySources().replace(DEFAULT_PROPERTIES,
769+
defaultProperties);
770+
}
771+
}
772+
773+
private List<String> getDefaultProfiles(Binder binder, String property) {
774+
return Arrays
775+
.asList(binder.bind(property, STRING_ARRAY).orElse(new String[] {}));
776+
}
777+
778+
}
779+
780+
private static class FilteredDefaultPropertySource extends MapPropertySource {
781+
782+
private static final List<String> FILTERED_PROPERTY = Arrays
783+
.asList("spring.profiles.active", "spring.profiles.include");
784+
785+
FilteredDefaultPropertySource(String name, Map<String, Object> source) {
786+
super(name, source);
787+
}
788+
789+
@Override
790+
public Object getProperty(String name) {
791+
if (isFilteredProperty(name)) {
792+
return null;
793+
}
794+
return super.getProperty(name);
795+
}
796+
797+
@Override
798+
public boolean containsProperty(String name) {
799+
if (isFilteredProperty(name)) {
800+
return false;
801+
}
802+
return super.containsProperty(name);
803+
}
804+
805+
@Override
806+
public String[] getPropertyNames() {
807+
return Arrays.stream(super.getPropertyNames())
808+
.filter((name) -> !isFilteredProperty(name)).toArray(String[]::new);
809+
}
810+
811+
protected boolean isFilteredProperty(String name) {
812+
return FILTERED_PROPERTY.contains(name);
813+
}
814+
732815
}
733816

734817
/**

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,51 @@ public void defaultPropertyAsFallbackDuringFileParsing() {
329329
assertThat(property).isEqualTo("frompropertiesfile");
330330
}
331331

332+
@Test
333+
public void activeProfilesFromDefaultPropertiesShouldNotTakePrecedence() {
334+
this.initializer.setSearchNames("enableprofile");
335+
this.environment.getPropertySources()
336+
.addLast(new MapPropertySource("defaultProperties",
337+
Collections.singletonMap("spring.profiles.active", "dev")));
338+
this.initializer.postProcessEnvironment(this.environment, this.application);
339+
assertThat(this.environment.getActiveProfiles()).containsExactly("myprofile");
340+
}
341+
342+
@Test
343+
public void includedProfilesFromDefaultPropertiesShouldNotTakePrecedence() {
344+
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
345+
"spring.profiles.active=morespecific");
346+
this.environment.getPropertySources()
347+
.addLast(new MapPropertySource("defaultProperties",
348+
Collections.singletonMap("spring.profiles.include", "dev")));
349+
this.initializer.postProcessEnvironment(this.environment, this.application);
350+
assertThat(this.environment.getActiveProfiles()).containsExactly("dev",
351+
"morespecific", "yetmorespecific");
352+
}
353+
354+
@Test
355+
public void activeAndIncludedProfilesFromDefaultProperties() {
356+
Map<String, Object> source = new HashMap<>();
357+
source.put("spring.profiles.include", "other");
358+
source.put("spring.profiles.active", "dev");
359+
this.environment.getPropertySources()
360+
.addLast(new MapPropertySource("defaultProperties", source));
361+
this.initializer.postProcessEnvironment(this.environment, this.application);
362+
assertThat(this.environment.getActiveProfiles()).containsExactly("other", "dev");
363+
}
364+
365+
@Test
366+
public void activeFromDefaultPropertiesShouldNotApplyIfProfilesHaveBeenActivatedBefore() {
367+
Map<String, Object> source = new HashMap<>();
368+
source.put("spring.profiles.active", "dev");
369+
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
370+
"spring.profiles.active=other");
371+
this.environment.getPropertySources()
372+
.addLast(new MapPropertySource("defaultProperties", source));
373+
this.initializer.postProcessEnvironment(this.environment, this.application);
374+
assertThat(this.environment.getActiveProfiles()).containsExactly("other");
375+
}
376+
332377
@Test
333378
public void loadPropertiesThenProfilePropertiesActivatedInSpringApplication() {
334379
// This should be the effect of calling

0 commit comments

Comments
 (0)