Consider aliases when checking descendants

Update `AliasedConfigurationPropertySource` to consider aliases in
`containsDescendantOf`.

Prior to this commit, given a source containing `example.name` with
a defined alias of `other.name -> example.name` calling
`containsDescendantOf("other")` would incorrectly return
`ConfigurationPropertyState.ABSENT`.

Closes gh-14967
This commit is contained in:
chang-chao 2018-10-26 00:40:08 +09:00 committed by Phillip Webb
parent 7bb6df4206
commit 256ca681fd
3 changed files with 43 additions and 6 deletions

View File

@ -16,6 +16,8 @@
package org.springframework.boot.context.properties.source; package org.springframework.boot.context.properties.source;
import java.util.Set;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -58,11 +60,17 @@ class AliasedConfigurationPropertySource implements ConfigurationPropertySource
if (result != ConfigurationPropertyState.ABSENT) { if (result != ConfigurationPropertyState.ABSENT) {
return result; return result;
} }
for (ConfigurationPropertyName alias : getAliases().getAliases(name)) { Set<ConfigurationPropertyName> aliasNames = this.aliases.getAllNames();
ConfigurationPropertyState aliasResult = this.source for (ConfigurationPropertyName configurationPropertyName : aliasNames) {
.containsDescendantOf(alias); boolean descendantPresentInAlias = this.aliases
if (aliasResult != ConfigurationPropertyState.ABSENT) { .getAliases(configurationPropertyName).stream()
return aliasResult; .filter(name::isAncestorOf).findFirst().isPresent();
if (descendantPresentInAlias) {
ConfigurationProperty configurationProperty = this.getSource()
.getConfigurationProperty(configurationPropertyName);
if (configurationProperty != null) {
return ConfigurationPropertyState.PRESENT;
}
} }
} }
return ConfigurationPropertyState.ABSENT; return ConfigurationPropertyState.ABSENT;

View File

@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
@ -74,4 +75,8 @@ public final class ConfigurationPropertyNameAliases {
.findFirst().orElse(null); .findFirst().orElse(null);
} }
public Set<ConfigurationPropertyName> getAllNames() {
return this.aliases.keySet();
}
} }

View File

@ -19,6 +19,8 @@ package org.springframework.boot.context.properties.source;
import org.junit.Test; import org.junit.Test;
import org.mockito.Answers; import org.mockito.Answers;
import org.springframework.boot.origin.Origin;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -105,8 +107,30 @@ public class AliasedConfigurationPropertySourceTests {
.willReturn(ConfigurationPropertyState.ABSENT); .willReturn(ConfigurationPropertyState.ABSENT);
given(source.containsDescendantOf(ConfigurationPropertyName.of("bar"))) given(source.containsDescendantOf(ConfigurationPropertyName.of("bar")))
.willReturn(ConfigurationPropertyState.PRESENT); .willReturn(ConfigurationPropertyState.PRESENT);
ConfigurationPropertyName barBar = ConfigurationPropertyName.of("bar.bar");
given(source.getConfigurationProperty(barBar)).willReturn(
new ConfigurationProperty(barBar, "barBarValue", mock(Origin.class)));
ConfigurationPropertySource aliased = source ConfigurationPropertySource aliased = source
.withAliases(new ConfigurationPropertyNameAliases("foo", "bar")); .withAliases(new ConfigurationPropertyNameAliases("bar.bar", "foo.foo"));
assertThat(aliased.containsDescendantOf(name))
.isEqualTo(ConfigurationPropertyState.PRESENT);
}
@Test
public void containsDescendantOfWhenPresentInAliasShouldReturnPresent() {
ConfigurationPropertyName name = ConfigurationPropertyName.of("baz");
ConfigurationPropertySource source = mock(ConfigurationPropertySource.class,
withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));
given(source.containsDescendantOf(name))
.willReturn(ConfigurationPropertyState.ABSENT);
ConfigurationPropertyName barFoo = ConfigurationPropertyName.of("bar.foo");
given(source.getConfigurationProperty(barFoo)).willReturn(
new ConfigurationProperty(barFoo, "barFooValue", mock(Origin.class)));
ConfigurationPropertySource aliased = source
.withAliases(new ConfigurationPropertyNameAliases("bar.foo", "baz.foo"));
assertThat(aliased.containsDescendantOf(name)) assertThat(aliased.containsDescendantOf(name))
.isEqualTo(ConfigurationPropertyState.PRESENT); .isEqualTo(ConfigurationPropertyState.PRESENT);
} }