Browse Source
We configure the `SystemEnvironmentPropertySource` as a `Prefixed` property source. When adapting this to a `ConfigurationPropertySource, a `PrefixedConfigurationPropertySource` will be created for it. A `PrefixedConfigurationPropertySource` will resolve property such as `foo.bar` to `my.foo.bar` for a prefix of `my`. Closes gh-3450pull/25445/head
14 changed files with 416 additions and 17 deletions
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2021 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.context.properties.source; |
||||||
|
|
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* A {@link ConfigurationPropertySource} supporting a prefix. |
||||||
|
* |
||||||
|
* @author Madhura Bhave |
||||||
|
*/ |
||||||
|
class PrefixedConfigurationPropertySource implements ConfigurationPropertySource { |
||||||
|
|
||||||
|
private final ConfigurationPropertySource source; |
||||||
|
|
||||||
|
private final String prefix; |
||||||
|
|
||||||
|
PrefixedConfigurationPropertySource(ConfigurationPropertySource source, String prefix) { |
||||||
|
Assert.notNull(source, "Source must not be null"); |
||||||
|
Assert.notNull(prefix, "Prefix must not be null"); |
||||||
|
this.source = source; |
||||||
|
this.prefix = prefix; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) { |
||||||
|
ConfigurationProperty configurationProperty = this.source.getConfigurationProperty(getPrefixedName(name)); |
||||||
|
if (configurationProperty == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return ConfigurationProperty.of(name, configurationProperty.getValue(), configurationProperty.getOrigin()); |
||||||
|
} |
||||||
|
|
||||||
|
private ConfigurationPropertyName getPrefixedName(ConfigurationPropertyName name) { |
||||||
|
String prefix = (StringUtils.hasText(this.prefix)) ? this.prefix + "." : ""; |
||||||
|
return ConfigurationPropertyName.of(prefix + name); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) { |
||||||
|
return this.source.containsDescendantOf(getPrefixedName(name)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object getUnderlyingSource() { |
||||||
|
return this.source.getUnderlyingSource(); |
||||||
|
} |
||||||
|
|
||||||
|
protected ConfigurationPropertySource getSource() { |
||||||
|
return this.source; |
||||||
|
} |
||||||
|
|
||||||
|
protected String getPrefix() { |
||||||
|
return this.prefix; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2021 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.context.properties.source; |
||||||
|
|
||||||
|
import java.util.stream.Stream; |
||||||
|
|
||||||
|
/** |
||||||
|
* An iterable {@link PrefixedConfigurationPropertySource}. |
||||||
|
* |
||||||
|
* @author Madhura Bhave |
||||||
|
*/ |
||||||
|
class PrefixedIterableConfigurationPropertySource extends PrefixedConfigurationPropertySource |
||||||
|
implements IterableConfigurationPropertySource { |
||||||
|
|
||||||
|
PrefixedIterableConfigurationPropertySource(IterableConfigurationPropertySource source, String prefix) { |
||||||
|
super(source, prefix); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Stream<ConfigurationPropertyName> stream() { |
||||||
|
ConfigurationPropertyName prefix = ConfigurationPropertyName.of(getPrefix()); |
||||||
|
return getSource().stream().map((propertyName) -> { |
||||||
|
if (prefix.isAncestorOf(propertyName)) { |
||||||
|
String name = propertyName.toString(); |
||||||
|
return ConfigurationPropertyName.of(name.substring(getPrefix().length() + 1)); |
||||||
|
} |
||||||
|
return propertyName; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected IterableConfigurationPropertySource getSource() { |
||||||
|
return (IterableConfigurationPropertySource) super.getSource(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2021 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.env; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface that can be implemented by a |
||||||
|
* {@link org.springframework.core.env.PropertySource} that can be used with a prefix. |
||||||
|
* |
||||||
|
* @author Madhura Bhave |
||||||
|
* @since 2.5.0 |
||||||
|
*/ |
||||||
|
@FunctionalInterface |
||||||
|
public interface Prefixed { |
||||||
|
|
||||||
|
String getPrefix(); |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,89 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2021 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.context.properties.source; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
import org.mockito.Answers; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.mockito.BDDMockito.given; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
|
||||||
|
/** |
||||||
|
* Tests for {@link PrefixedConfigurationPropertySource}. |
||||||
|
* |
||||||
|
* @author Madhura Bhave |
||||||
|
*/ |
||||||
|
class PrefixedConfigurationPropertySourceTests { |
||||||
|
|
||||||
|
@Test |
||||||
|
void getConfigurationPropertyShouldConsiderPrefix() { |
||||||
|
MockConfigurationPropertySource source = new MockConfigurationPropertySource(); |
||||||
|
source.put("my.foo.bar", "bing"); |
||||||
|
source.put("my.foo.baz", "biff"); |
||||||
|
ConfigurationPropertySource prefixed = source.nonIterable().withPrefix("my"); |
||||||
|
assertThat(getName(prefixed, "foo.bar").toString()).isEqualTo("foo.bar"); |
||||||
|
assertThat(getValue(prefixed, "foo.bar")).isEqualTo("bing"); |
||||||
|
assertThat(getName(prefixed, "foo.baz").toString()).isEqualTo("foo.baz"); |
||||||
|
assertThat(getValue(prefixed, "foo.baz")).isEqualTo("biff"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void containsDescendantOfWhenSourceReturnsUnknownShouldReturnUnknown() { |
||||||
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.foo"); |
||||||
|
ConfigurationPropertySource source = mock(ConfigurationPropertySource.class, Answers.CALLS_REAL_METHODS); |
||||||
|
given(source.containsDescendantOf(name)).willReturn(ConfigurationPropertyState.UNKNOWN); |
||||||
|
ConfigurationPropertySource prefixed = source.withPrefix("my"); |
||||||
|
assertThat(prefixed.containsDescendantOf(ConfigurationPropertyName.of("foo"))) |
||||||
|
.isEqualTo(ConfigurationPropertyState.UNKNOWN); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void containsDescendantOfWhenSourceReturnsPresentShouldReturnPresent() { |
||||||
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.foo"); |
||||||
|
ConfigurationPropertySource source = mock(ConfigurationPropertySource.class, Answers.CALLS_REAL_METHODS); |
||||||
|
given(source.containsDescendantOf(name)).willReturn(ConfigurationPropertyState.PRESENT); |
||||||
|
given(source.containsDescendantOf(ConfigurationPropertyName.of("bar"))) |
||||||
|
.willReturn(ConfigurationPropertyState.UNKNOWN); |
||||||
|
ConfigurationPropertySource prefixed = source.withPrefix("my"); |
||||||
|
assertThat(prefixed.containsDescendantOf(ConfigurationPropertyName.of("foo"))) |
||||||
|
.isEqualTo(ConfigurationPropertyState.PRESENT); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void containsDescendantOfWhenSourceReturnsAbsentShouldReturnAbsent() { |
||||||
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.foo"); |
||||||
|
ConfigurationPropertySource source = mock(ConfigurationPropertySource.class, Answers.CALLS_REAL_METHODS); |
||||||
|
given(source.containsDescendantOf(name)).willReturn(ConfigurationPropertyState.ABSENT); |
||||||
|
given(source.containsDescendantOf(ConfigurationPropertyName.of("bar"))) |
||||||
|
.willReturn(ConfigurationPropertyState.ABSENT); |
||||||
|
ConfigurationPropertySource prefixed = source.withPrefix("my"); |
||||||
|
assertThat(prefixed.containsDescendantOf(ConfigurationPropertyName.of("foo"))) |
||||||
|
.isEqualTo(ConfigurationPropertyState.ABSENT); |
||||||
|
} |
||||||
|
|
||||||
|
private ConfigurationPropertyName getName(ConfigurationPropertySource source, String name) { |
||||||
|
ConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name)); |
||||||
|
return (property != null) ? property.getName() : null; |
||||||
|
} |
||||||
|
|
||||||
|
private Object getValue(ConfigurationPropertySource source, String name) { |
||||||
|
ConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name)); |
||||||
|
return (property != null) ? property.getValue() : null; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,41 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2021 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.context.properties.source; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* Tests for {@link PrefixedIterableConfigurationPropertySource}. |
||||||
|
* |
||||||
|
* @author Madhura Bhave |
||||||
|
*/ |
||||||
|
class PrefixedIterableConfigurationPropertySourceTests { |
||||||
|
|
||||||
|
@Test |
||||||
|
void streamShouldConsiderPrefix() { |
||||||
|
MockConfigurationPropertySource source = new MockConfigurationPropertySource(); |
||||||
|
source.put("my.foo.bar", "bing"); |
||||||
|
source.put("my.foo.baz", "biff"); |
||||||
|
source.put("hello.bing", "blah"); |
||||||
|
IterableConfigurationPropertySource prefixed = source.withPrefix("my"); |
||||||
|
assertThat(prefixed.stream()).containsExactly(ConfigurationPropertyName.of("foo.bar"), |
||||||
|
ConfigurationPropertyName.of("foo.baz"), ConfigurationPropertyName.of("hello.bing")); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue