Merge config from custom locations with default configuration
Previously, when one or more custom locations were specified on @ConfigurationProperties, the configuration loaded from those locations was used in isolation from the default configuration provided by the environment. Users have been surprised by this behaviour. For example, it means that a placeholder used in the custom configuration will not be resolved against the system properties. This commit adds a new attribute, merge, to @ConfigurationProperties, that defaults to true. When merge is true the default property sources are appended to those that are loaded from the custom locations. When set to false the custom configuration is used in isolation. Closes #1301
This commit is contained in:
parent
1e51c5db15
commit
5f8c1e77cc
|
|
@ -78,10 +78,20 @@ public @interface ConfigurationProperties {
|
||||||
boolean exceptionIfInvalid() default true;
|
boolean exceptionIfInvalid() default true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optionally provide an explicit resource locations to bind to instead of using the
|
* Optionally provide explicit resource locations to bind to. By default the
|
||||||
* default environment.
|
* configuration at these specified locations will be merged with the default
|
||||||
|
* configuration.
|
||||||
* @return the path (or paths) of resources to bind to
|
* @return the path (or paths) of resources to bind to
|
||||||
|
* @see #merge()
|
||||||
*/
|
*/
|
||||||
String[] locations() default {};
|
String[] locations() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to indicate that configuration loaded from the specified locations should be
|
||||||
|
* merged with the default configuration.
|
||||||
|
* @return the flag value (default true)
|
||||||
|
* @see #locations()
|
||||||
|
*/
|
||||||
|
boolean merge() default true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,8 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
|
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
|
||||||
target);
|
target);
|
||||||
if (annotation != null && annotation.locations().length != 0) {
|
if (annotation != null && annotation.locations().length != 0) {
|
||||||
factory.setPropertySources(loadPropertySources(annotation.locations()));
|
factory.setPropertySources(loadPropertySources(annotation.locations(),
|
||||||
|
annotation.merge()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
factory.setPropertySources(this.propertySources);
|
factory.setPropertySources(this.propertySources);
|
||||||
|
|
@ -301,7 +302,8 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
return this.validator;
|
return this.validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertySources loadPropertySources(String[] locations) {
|
private PropertySources loadPropertySources(String[] locations,
|
||||||
|
boolean mergeDefaultSources) {
|
||||||
try {
|
try {
|
||||||
PropertySourcesLoader loader = new PropertySourcesLoader();
|
PropertySourcesLoader loader = new PropertySourcesLoader();
|
||||||
for (String location : locations) {
|
for (String location : locations) {
|
||||||
|
|
@ -314,7 +316,14 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
}
|
}
|
||||||
loader.load(resource);
|
loader.load(resource);
|
||||||
}
|
}
|
||||||
return loader.getPropertySources();
|
|
||||||
|
MutablePropertySources loaded = loader.getPropertySources();
|
||||||
|
if (mergeDefaultSources) {
|
||||||
|
for (PropertySource<?> propertySource : this.propertySources) {
|
||||||
|
loaded.addLast(propertySource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loaded;
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
throw new IllegalStateException(ex);
|
throw new IllegalStateException(ex);
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,26 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
equalTo("foo"));
|
equalTo("foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void placeholderResolutionWithCustomLocation() throws Exception {
|
||||||
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context, "fooValue:bar");
|
||||||
|
this.context.register(CustomConfigurationLocation.class);
|
||||||
|
this.context.refresh();
|
||||||
|
assertThat(this.context.getBean(CustomConfigurationLocation.class).getFoo(),
|
||||||
|
equalTo("bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void placeholderResolutionWithUnmergedCustomLocation() throws Exception {
|
||||||
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context, "fooValue:bar");
|
||||||
|
this.context.register(UnmergedCustomConfigurationLocation.class);
|
||||||
|
this.context.refresh();
|
||||||
|
assertThat(this.context.getBean(UnmergedCustomConfigurationLocation.class)
|
||||||
|
.getFoo(), equalTo("${fooValue}"));
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties
|
@EnableConfigurationProperties
|
||||||
public static class TestConfigurationWithValidatingSetter {
|
public static class TestConfigurationWithValidatingSetter {
|
||||||
|
|
@ -299,4 +319,36 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EnableConfigurationProperties
|
||||||
|
@ConfigurationProperties(locations = "custom-location.yml")
|
||||||
|
public static class CustomConfigurationLocation {
|
||||||
|
|
||||||
|
private String foo;
|
||||||
|
|
||||||
|
public String getFoo() {
|
||||||
|
return this.foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFoo(String foo) {
|
||||||
|
this.foo = foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableConfigurationProperties
|
||||||
|
@ConfigurationProperties(locations = "custom-location.yml", merge = false)
|
||||||
|
public static class UnmergedCustomConfigurationLocation {
|
||||||
|
|
||||||
|
private String foo;
|
||||||
|
|
||||||
|
public String getFoo() {
|
||||||
|
return this.foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFoo(String foo) {
|
||||||
|
this.foo = foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
foo: ${fooValue}
|
||||||
Loading…
Reference in New Issue