Skip to content

Commit

Permalink
Add additional profiles to ConfigFileApplicationListener
Browse files Browse the repository at this point in the history
Add additional profiles which is set via 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 is set via programmatically,
to ConfigFileApplicationListener from ConfigDataEnvironmentPostProcessor

- Add additional profiles into Spring's environment property sources

- Supplement unit test for SpringApplicationTests

Closes #25704
  • Loading branch information
nguyensach committed Mar 29, 2021
1 parent 269fc68 commit 1aa39f5
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
*
* @author Phillip Webb
* @author Madhura Bhave
* @author Nguyen Bao Sach
* @since 2.4.0
*/
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
Expand Down Expand Up @@ -99,7 +100,7 @@ void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader
catch (UseLegacyConfigProcessingException ex) {
this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]",
ex.getConfigurationProperty()));
postProcessUsingLegacyApplicationListener(environment, resourceLoader);
postProcessUsingLegacyApplicationListener(environment, resourceLoader, additionalProfiles);
}
}

Expand All @@ -110,13 +111,14 @@ ConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environme
}

private void postProcessUsingLegacyApplicationListener(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
getLegacyListener().addPropertySources(environment, resourceLoader);
ResourceLoader resourceLoader, Collection<String> additionalProfiles) {
getLegacyListener(additionalProfiles).addPropertySources(environment, resourceLoader);
}

@SuppressWarnings("deprecation")
LegacyConfigFileApplicationListener getLegacyListener() {
return new LegacyConfigFileApplicationListener(this.logFactory.getLog(ConfigFileApplicationListener.class));
LegacyConfigFileApplicationListener getLegacyListener(Collection<String> additionalProfiles) {
return new LegacyConfigFileApplicationListener(this.logFactory.getLog(ConfigFileApplicationListener.class),
additionalProfiles);
}

/**
Expand Down Expand Up @@ -189,8 +191,8 @@ public static void applyTo(ConfigurableEnvironment environment, ResourceLoader r
@SuppressWarnings("deprecation")
static class LegacyConfigFileApplicationListener extends ConfigFileApplicationListener {

LegacyConfigFileApplicationListener(Log logger) {
super(logger);
LegacyConfigFileApplicationListener(Log logger, Collection<String> additionalProfiles) {
super(logger, additionalProfiles);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,7 @@
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -111,6 +98,7 @@
* @author Eddú Meléndez
* @author Madhura Bhave
* @author Scott Frederick
* @author Nguyen Bao Sach
* @since 1.0.0
* @deprecated since 2.4.0 in favor of {@link ConfigDataEnvironmentPostProcessor}
*/
Expand Down Expand Up @@ -179,6 +167,8 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,

private int order = DEFAULT_ORDER;

private Collection<String> additionalProfiles = Collections.emptySet();

public ConfigFileApplicationListener() {
this(new DeferredLog());
}
Expand All @@ -187,6 +177,11 @@ public ConfigFileApplicationListener() {
this.logger = logger;
}

ConfigFileApplicationListener(Log logger, Collection<String> additionalProfiles) {
this.logger = logger;
this.additionalProfiles = additionalProfiles;
}

@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
Expand Down Expand Up @@ -353,11 +348,14 @@ private void initializeProfiles() {
Binder binder = Binder.get(this.environment);
Set<Profile> activatedViaProperty = getProfiles(binder, ACTIVE_PROFILES_PROPERTY);
Set<Profile> includedViaProperty = getProfiles(binder, INCLUDE_PROFILES_PROPERTY);
List<Profile> otherActiveProfiles = getOtherActiveProfiles(activatedViaProperty, includedViaProperty);
Set<Profile> additionalProfiles = asProfileSet(
ConfigFileApplicationListener.this.additionalProfiles.toArray(new String[0]));
additionalProfiles.addAll(includedViaProperty);
List<Profile> otherActiveProfiles = getOtherActiveProfiles(activatedViaProperty, additionalProfiles);
this.profiles.addAll(otherActiveProfiles);
// Any pre-existing active profiles set via property sources (e.g.
// System properties) take precedence over those added in config files.
this.profiles.addAll(includedViaProperty);
this.profiles.addAll(additionalProfiles);
addActiveProfiles(activatedViaProperty);
if (this.profiles.size() == 1) { // only has null profile
for (String defaultProfileName : this.environment.getDefaultProfiles()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
* @author Brian Clozel
* @author Artsiom Yudovin
* @author Marten Deinum
* @author Nguyen Bao Sach
*/
@ExtendWith(OutputCaptureExtension.class)
class SpringApplicationTests {
Expand Down Expand Up @@ -604,6 +605,17 @@ void addProfilesOrder() {
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
}

@Test
void includeProfilesOrder() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
ConfigurableEnvironment environment = new StandardEnvironment();
application.setEnvironment(environment);
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
// Since Boot 2.4 included profiles should always be last
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
}

@Test
void addProfilesOrderWithProperties() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
*
* @author Phillip Webb
* @author Madhura Bhave
* @author Nguyen Bao Sach
*/
@ExtendWith(MockitoExtension.class)
class ConfigDataEnvironmentPostProcessorTests {
Expand Down Expand Up @@ -111,10 +112,25 @@ void postProcessEnvironmentWhenUseLegacyProcessingSwitchesToLegacyMethod() {
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener.class);
willThrow(new UseLegacyConfigProcessingException(null)).given(this.postProcessor)
.getConfigDataEnvironment(any(), any(), any());
willReturn(legacyListener).given(this.postProcessor).getLegacyListener();
willReturn(legacyListener).given(this.postProcessor).getLegacyListener(this.additionalProfilesCaptor.capture());
this.postProcessor.postProcessEnvironment(this.environment, this.application);
verifyNoInteractions(this.configDataEnvironment);
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
assertThat(this.additionalProfilesCaptor.getValue()).isEmpty();
}

@Test
void postProcessEnvironmentWhenHasAdditionalProfilesViaProgrammaticallySettingAndUseLegacyProcessing() {
this.application.setAdditionalProfiles("dev");
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener legacyListener = mock(
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener.class);
willThrow(new UseLegacyConfigProcessingException(null)).given(this.postProcessor)
.getConfigDataEnvironment(any(), any(), any());
willReturn(legacyListener).given(this.postProcessor).getLegacyListener(this.additionalProfilesCaptor.capture());
this.postProcessor.postProcessEnvironment(this.environment, this.application);
verifyNoInteractions(this.configDataEnvironment);
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
assertThat(this.additionalProfilesCaptor.getValue()).containsExactly("dev");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
*
* @author Phillip Webb
* @author Dave Syer
* @author Nguyen Bao Sach
*/
@ExtendWith(UseLegacyProcessing.class)
class ConfigFileApplicationListenerLegacyReproTests {
Expand Down Expand Up @@ -167,6 +168,17 @@ void reverseOrderOfProfilesWithYamlAndNoOverride() {
assertVersionProperty(this.context, "A", "C", "A");
}

@Test
void additionalProfilesViaProgrammaticallySetting() {
// gh-25704
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("dev");
this.context = application.run();
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("dev"))).isTrue();
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
}

private void assertVersionProperty(ConfigurableApplicationContext context, String expectedVersion,
String... expectedActiveProfiles) {
assertThat(context.getEnvironment().getActiveProfiles()).isEqualTo(expectedActiveProfiles);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@

package org.springframework.boot.context.config;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.logging.log4j.Level;
Expand All @@ -46,11 +35,8 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.Profiles;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.env.*;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
Expand All @@ -59,6 +45,13 @@
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

Expand All @@ -70,6 +63,7 @@
* @author Eddú Meléndez
* @author Madhura Bhave
* @author Scott Frederick
* @author Nguyen Bao Sach
*/
@Deprecated
@ExtendWith({ OutputCaptureExtension.class, UseLegacyProcessing.class })
Expand Down Expand Up @@ -1150,6 +1144,46 @@ void locationsWithWildcardFilesShouldIgnoreHiddenDirectories() {
assertThat(this.environment.getProperty("fourth.property")).isNull();
}

@Test
void additionalProfilesCanBeIncludedFromProgrammaticallySetting() {
// gh-25704
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("dev");
this.context = application.run();
// Active profile should win over default
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
}

@Test
void twoAdditionalProfilesCanBeIncludedFromProgrammaticallySetting() {
// gh-25704
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("other", "dev");
this.context = application.run();
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
}

@Test
void includeProfilesOrder() {
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
// Before Boot 2.4 included profiles should always be first
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
}

@Test
void addProfilesOrder() {
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("foo");
this.context = application.run("--spring.profiles.active=bar,spam");
// Before Boot 2.4 additional profiles should always be first
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
}

private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {
return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) {

Expand Down

0 comments on commit 1aa39f5

Please sign in to comment.