Skip to content

Commit

Permalink
Merge branch '2.4.x'
Browse files Browse the repository at this point in the history
Closes gh-26580
  • Loading branch information
philwebb committed May 17, 2021
2 parents de60097 + cfa2673 commit 634d276
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.function.Function;

import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
Expand Down Expand Up @@ -61,9 +62,7 @@ public class Profiles implements Iterable<String> {
private static final Bindable<MultiValueMap<String, String>> STRING_STRINGS_MAP = Bindable
.of(ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class));

private static final Set<String> UNSET_ACTIVE = Collections.emptySet();

private static final Set<String> UNSET_DEFAULT = Collections.singleton("default");
private static final Bindable<Set<String>> STRING_SET = Bindable.setOf(String.class);

private final MultiValueMap<String, String> groups;

Expand All @@ -86,35 +85,42 @@ public class Profiles implements Iterable<String> {

private List<String> getActivatedProfiles(Environment environment, Binder binder,
Collection<String> additionalProfiles) {
return asUniqueItemList(get(environment, binder, environment::getActiveProfiles,
AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, UNSET_ACTIVE), additionalProfiles);
return asUniqueItemList(getProfiles(environment, binder, Type.ACTIVE), additionalProfiles);
}

private List<String> getDefaultProfiles(Environment environment, Binder binder) {
return asUniqueItemList(get(environment, binder, environment::getDefaultProfiles,
AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME, UNSET_DEFAULT));
return asUniqueItemList(getProfiles(environment, binder, Type.DEFAULT));
}

private String[] get(Environment environment, Binder binder, Supplier<String[]> supplier, String propertyName,
Set<String> unset) {
String propertyValue = environment.getProperty(propertyName);
if (hasExplicit(supplier, propertyValue, unset)) {
return supplier.get();
private Collection<String> getProfiles(Environment environment, Binder binder, Type type) {
String environmentPropertyValue = environment.getProperty(type.getName());
Set<String> environmentPropertyProfiles = (!StringUtils.hasLength(environmentPropertyValue))
? Collections.emptySet()
: StringUtils.commaDelimitedListToSet(StringUtils.trimAllWhitespace(environmentPropertyValue));
Set<String> environmentProfiles = new LinkedHashSet<>(Arrays.asList(type.get(environment)));
BindResult<Set<String>> boundProfiles = binder.bind(type.getName(), STRING_SET);
if (hasProgrammaticallySetProfiles(type, environmentPropertyValue, environmentPropertyProfiles,
environmentProfiles)) {
if (!type.isMergeWithEnvironmentProfiles() || !boundProfiles.isBound()) {
return environmentProfiles;
}
return boundProfiles.map((bound) -> merge(environmentProfiles, bound)).get();
}
return binder.bind(propertyName, String[].class).orElseGet(() -> StringUtils.toStringArray(unset));
return boundProfiles.orElse(type.getDefaultValue());
}

private boolean hasExplicit(Supplier<String[]> supplier, String propertyValue, Set<String> unset) {
Set<String> profiles = new LinkedHashSet<>(Arrays.asList(supplier.get()));
if (!StringUtils.hasLength(propertyValue)) {
return !unset.equals(profiles);
private boolean hasProgrammaticallySetProfiles(Type type, String environmentPropertyValue,
Set<String> environmentPropertyProfiles, Set<String> environmentProfiles) {
if (!StringUtils.hasLength(environmentPropertyValue)) {
return !type.getDefaultValue().equals(environmentProfiles);
}
if (unset.equals(profiles)) {
return false;
}
Set<String> propertyProfiles = StringUtils
.commaDelimitedListToSet(StringUtils.trimAllWhitespace(propertyValue));
return !propertyProfiles.equals(profiles);
return !environmentPropertyProfiles.equals(environmentProfiles);
}

private Set<String> merge(Set<String> environmentProfiles, Set<String> bound) {
Set<String> result = new LinkedHashSet<>(environmentProfiles);
result.addAll(bound);
return result;
}

private List<String> expandProfiles(List<String> profiles) {
Expand All @@ -127,7 +133,7 @@ private List<String> expandProfiles(List<String> profiles) {
asReversedList(this.groups.get(current)).forEach(stack::push);
}
}
return asUniqueItemList(StringUtils.toStringArray(expandedProfiles));
return asUniqueItemList(expandedProfiles);
}

private List<String> asReversedList(List<String> list) {
Expand All @@ -139,12 +145,12 @@ private List<String> asReversedList(List<String> list) {
return reversed;
}

private List<String> asUniqueItemList(String[] array) {
return asUniqueItemList(array, null);
private List<String> asUniqueItemList(Collection<String> strings) {
return asUniqueItemList(strings, null);
}

private List<String> asUniqueItemList(String[] array, Collection<String> additional) {
LinkedHashSet<String> uniqueItems = new LinkedHashSet<>(Arrays.asList(array));
private List<String> asUniqueItemList(Collection<String> strings, Collection<String> additional) {
LinkedHashSet<String> uniqueItems = new LinkedHashSet<>(strings);
if (!CollectionUtils.isEmpty(additional)) {
uniqueItems.addAll(additional);
}
Expand Down Expand Up @@ -201,4 +207,49 @@ public String toString() {
return creator.toString();
}

/**
* A profiles type that can be obtained.
*/
private enum Type {

ACTIVE(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, Environment::getActiveProfiles, true,
Collections.emptySet()),

DEFAULT(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME, Environment::getDefaultProfiles, false,
Collections.singleton("default"));

private final Function<Environment, String[]> getter;

private final boolean mergeWithEnvironmentProfiles;

private final String name;

private final Set<String> defaultValue;

Type(String name, Function<Environment, String[]> getter, boolean mergeWithEnvironmentProfiles,
Set<String> defaultValue) {
this.name = name;
this.getter = getter;
this.mergeWithEnvironmentProfiles = mergeWithEnvironmentProfiles;
this.defaultValue = defaultValue;
}

String getName() {
return this.name;
}

String[] get(Environment environment) {
return this.getter.apply(environment);
}

Set<String> getDefaultValue() {
return this.defaultValue;
}

boolean isMergeWithEnvironmentProfiles() {
return this.mergeWithEnvironmentProfiles;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

package org.springframework.boot.context.config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;

import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.core.env.Environment;
import org.springframework.mock.env.MockEnvironment;
Expand Down Expand Up @@ -69,6 +73,18 @@ void getActiveWhenEnvironmentProfilesAndBinderProperty() {
Binder binder = new Binder(
new MapConfigurationPropertySource(Collections.singletonMap("spring.profiles.active", "d,e,f")));
Profiles profiles = new Profiles(environment, binder, null);
assertThat(profiles.getActive()).containsExactly("a", "b", "c", "d", "e", "f");
}

@Test
void getActiveWhenEnvironmentProfilesAndBinderPropertyShouldReturnEnvironmentProperty() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("spring.profiles.active", "a,b,c");
List<ConfigurationPropertySource> sources = new ArrayList<>();
ConfigurationPropertySources.get(environment).forEach(sources::add);
sources.add(new MapConfigurationPropertySource(Collections.singletonMap("spring.profiles.active", "d,e,f")));
Binder binder = new Binder(sources);
Profiles profiles = new Profiles(environment, binder, null);
assertThat(profiles.getActive()).containsExactly("a", "b", "c");
}

Expand All @@ -79,7 +95,7 @@ void getActiveWhenEnvironmentProfilesAndEnvironmentProperty() {
environment.setProperty("spring.profiles.active", "d,e,f");
Binder binder = Binder.get(environment);
Profiles profiles = new Profiles(environment, binder, null);
assertThat(profiles.getActive()).containsExactly("a", "b", "c");
assertThat(profiles.getActive()).containsExactly("a", "b", "c", "d", "e", "f");
}

@Test
Expand All @@ -102,7 +118,7 @@ void getActiveWhenEnvironmentProfilesInBindNotationAndEnvironmentPropertyReturns
environment.setProperty("spring.profiles.active[2]", "f");
Binder binder = Binder.get(environment);
Profiles profiles = new Profiles(environment, binder, null);
assertThat(profiles.getActive()).containsExactly("a", "b", "c");
assertThat(profiles.getActive()).containsExactly("a", "b", "c", "d", "e", "f");
}

@Test
Expand Down Expand Up @@ -150,6 +166,18 @@ void getDefaultWhenNoEnvironmentProfilesAndBinderProperty() {
assertThat(profiles.getDefault()).containsExactly("a", "b", "c");
}

@Test
void getDefaultWhenDefaultEnvironmentProfileAndBinderProperty() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("spring.profiles.default", "default");
List<ConfigurationPropertySource> sources = new ArrayList<>();
ConfigurationPropertySources.get(environment).forEach(sources::add);
sources.add(new MapConfigurationPropertySource(Collections.singletonMap("spring.profiles.default", "a,b,c")));
Binder binder = new Binder(sources);
Profiles profiles = new Profiles(environment, binder, null);
assertThat(profiles.getDefault()).containsExactly("default");
}

@Test
void getDefaultWhenNoEnvironmentProfilesAndEnvironmentProperty() {
MockEnvironment environment = new MockEnvironment();
Expand Down Expand Up @@ -210,7 +238,7 @@ void getDefaultWithProfileGroups() {
}

@Test
void getDefaultWhenEnvironmentProfilesInBindNotationAndEnvironmentPropertyReturnsEnvironmentProfiles() {
void getDefaultWhenEnvironmentProfilesInBindNotationAndEnvironmentPropertyReturnsBoth() {
MockEnvironment environment = new MockEnvironment();
environment.setDefaultProfiles("a", "b", "c");
environment.setProperty("spring.profiles.default[0]", "d");
Expand Down

0 comments on commit 634d276

Please sign in to comment.