From 5b74f77ac65631e10a5a3e14f74805af4e03a150 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Fri, 4 Dec 2020 00:03:19 +0100 Subject: [PATCH] Fail on recursive references in profile groups Update `Profiles` group expansion logic to fail if recursive references are found. See gh-24327 --- .../boot/context/config/Profiles.java | 17 ++++++++++++-- .../boot/context/config/ProfilesTests.java | 22 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java index 2e8ec6e760..3e6e6b0434 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java @@ -27,6 +27,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.function.Supplier; +import java.util.stream.Collectors; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; @@ -117,18 +118,30 @@ public class Profiles implements Iterable { while (!stack.isEmpty()) { String current = stack.pop(); expandedProfiles.add(current); - asReversedList(this.groups.get(current)).forEach(stack::push); + List groupProfiles = asReversedList(this.groups.get(current)); + Set profileConflicts = getProfileConflicts(groupProfiles, expandedProfiles); + if (!profileConflicts.isEmpty()) { + String message = String.format("Profiles could not be resolved. Remove profiles %s from group: %s", + profileConflicts, current); + throw new IllegalStateException(message); + + } + groupProfiles.forEach(stack::push); } return asUniqueItemList(StringUtils.toStringArray(expandedProfiles)); } + private Set getProfileConflicts(List groupProfiles, Set expandedProfiles) { + return groupProfiles.stream().filter(expandedProfiles::contains).collect(Collectors.toSet()); + } + private List asReversedList(List list) { if (list == null || list.isEmpty()) { return Collections.emptyList(); } List reversed = new ArrayList<>(list); Collections.reverse(reversed); - return Collections.unmodifiableList(reversed); + return reversed; } private List asUniqueItemList(String[] array) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ProfilesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ProfilesTests.java index 5271fc52b2..39db2198de 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ProfilesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ProfilesTests.java @@ -27,6 +27,7 @@ import org.springframework.core.env.Environment; import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; /** * Tests for {@link Profiles}. @@ -359,4 +360,25 @@ class ProfilesTests { assertThat(profiles.isAccepted("x")).isTrue(); } + @Test + void simpleRecursiveReferenceInProfileGroupThrowsException() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.profiles.active", "a,b,c"); + environment.setProperty("spring.profiles.group.a", "a,e,f"); + Binder binder = Binder.get(environment); + assertThatIllegalStateException().isThrownBy(() -> new Profiles(environment, binder, null)) + .withMessageContaining("Profiles could not be resolved. Remove profiles [a] from group: a"); + } + + @Test + void complexRecursiveReferenceInProfileGroupThrowsException() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.profiles.active", "a,b,c"); + environment.setProperty("spring.profiles.group.a", "e,f"); + environment.setProperty("spring.profiles.group.e", "a,x,y"); + Binder binder = Binder.get(environment); + assertThatIllegalStateException().isThrownBy(() -> new Profiles(environment, binder, null)) + .withMessageContaining("Profiles could not be resolved. Remove profiles [a] from group: e"); + } + }