diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java index 6da6fca3891..ca780fe2e19 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java @@ -78,10 +78,20 @@ public @interface ConfigurationProperties { boolean exceptionIfInvalid() default true; /** - * Optionally provide an explicit resource locations to bind to instead of using the - * default environment. + * Optionally provide explicit resource locations to bind to. By default the + * configuration at these specified locations will be merged with the default + * configuration. * @return the path (or paths) of resources to bind to + * @see #merge() */ 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; + } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java index 6dff66b337b..dd4876b8d66 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java @@ -262,7 +262,8 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory( target); if (annotation != null && annotation.locations().length != 0) { - factory.setPropertySources(loadPropertySources(annotation.locations())); + factory.setPropertySources(loadPropertySources(annotation.locations(), + annotation.merge())); } else { factory.setPropertySources(this.propertySources); @@ -301,7 +302,8 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc return this.validator; } - private PropertySources loadPropertySources(String[] locations) { + private PropertySources loadPropertySources(String[] locations, + boolean mergeDefaultSources) { try { PropertySourcesLoader loader = new PropertySourcesLoader(); for (String location : locations) { @@ -314,7 +316,14 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc } 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) { throw new IllegalStateException(ex); diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java index 50c55a0e9ae..58367b127fb 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java @@ -141,6 +141,26 @@ public class ConfigurationPropertiesBindingPostProcessorTests { 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 @EnableConfigurationProperties 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; + } + + } + } diff --git a/spring-boot/src/test/resources/custom-location.yml b/spring-boot/src/test/resources/custom-location.yml new file mode 100644 index 00000000000..60000ea2327 --- /dev/null +++ b/spring-boot/src/test/resources/custom-location.yml @@ -0,0 +1 @@ +foo: ${fooValue} \ No newline at end of file