diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java index d62b5e9ed25..04a35d9abf2 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java @@ -37,9 +37,20 @@ import org.springframework.core.env.Environment; public @interface ConditionalOnProperty { /** - * One or more properties that must be present. + * A prefix that should be applied to each property. + */ + String prefix() default ""; + + /** + * One or more properties that must be present. If you are checking relaxed names you + * should specify the property in its dashed form. * @return the property names */ String[] value(); + /** + * If relaxed names should be checked. Defaults to {@code true}. + */ + boolean relaxedNames() default true; + } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyCondition.java index 1508a7ae3bc..5bb2fa93582 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyCondition.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyCondition.java @@ -19,9 +19,10 @@ package org.springframework.boot.autoconfigure.condition; import java.util.ArrayList; import java.util.List; +import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertyResolver; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.StringUtils; @@ -29,6 +30,7 @@ import org.springframework.util.StringUtils; * {@link Condition} that checks if properties are defined in environment. * * @author Maciej Walkowiak + * @author Phillip Webb * @see ConditionalOnProperty * @since 1.1.0 */ @@ -38,17 +40,27 @@ class OnPropertyCondition extends SpringBootCondition { public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - String[] onProperties = (String[]) metadata.getAnnotationAttributes( + String prefix = (String) metadata.getAnnotationAttributes( + ConditionalOnProperty.class.getName()).get("prefix"); + String[] names = (String[]) metadata.getAnnotationAttributes( ConditionalOnProperty.class.getName()).get("value"); + Boolean relaxedNames = (Boolean) metadata.getAnnotationAttributes( + ConditionalOnProperty.class.getName()).get("relaxedNames"); List missingProperties = new ArrayList(); - Environment environment = context.getEnvironment(); - for (String property : onProperties) { - if (!environment.containsProperty(property) - || StringUtils.endsWithIgnoreCase(environment.getProperty(property), - "false")) { - missingProperties.add(property); + PropertyResolver resolver = context.getEnvironment(); + if (relaxedNames) { + resolver = new RelaxedPropertyResolver(resolver, prefix); + prefix = ""; + } + + for (String name : names) { + name = prefix + name; + if (!resolver.containsProperty(name) + || "false".equalsIgnoreCase(resolver.getProperty(name))) { + missingProperties.add(name); + } } @@ -56,9 +68,9 @@ class OnPropertyCondition extends SpringBootCondition { return ConditionOutcome.match(); } - return ConditionOutcome - .noMatch("@ConditionalOnProperty missing required properties: " - + StringUtils.arrayToCommaDelimitedString(missingProperties - .toArray()) + " not found"); + return ConditionOutcome.noMatch("@ConditionalOnProperty " + + "missing required properties: " + + StringUtils.arrayToCommaDelimitedString(missingProperties.toArray()) + + " not found"); } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyTests.java index 020358846f2..18e231bdae0 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyTests.java @@ -22,7 +22,6 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -36,41 +35,57 @@ public class ConditionalOnPropertyTests { private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); @Test - public void testBeanIsCreatedWhenAllPropertiesAreDefined() { + public void allPropertiesAreDefined() { EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), "property1=value1", "property2=value2"); - setupContext(); - assertTrue(this.context.containsBean("foo")); - assertEquals("foo", this.context.getBean("foo")); - } - - @Test - public void testBeanIsNotCreatedWhenNotAllPropertiesAreDefined() { - EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), - "property1=value1"); - setupContext(); - assertFalse(this.context.containsBean("foo")); - } - - @Test - public void testBeanIsNotCreatedWhenPropertyValueEqualsFalse() { - EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), - "property1=false", "property2=value2"); - setupContext(); - assertFalse(this.context.containsBean("foo")); - } - - @Test - public void testBeanIsNotCreatedWhenPropertyValueEqualsFALSE() { - EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), - "property1=FALSE", "property2=value2"); - setupContext(); - assertFalse(this.context.containsBean("foo")); - } - - private void setupContext() { this.context.register(MultiplePropertiesRequiredConfiguration.class); this.context.refresh(); + assertTrue(this.context.containsBean("foo")); + } + + @Test + public void notAllPropertiesAreDefined() { + EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), + "property1=value1"); + this.context.register(MultiplePropertiesRequiredConfiguration.class); + this.context.refresh(); + assertFalse(this.context.containsBean("foo")); + } + + @Test + public void propertyValueEqualsFalse() { + EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), + "property1=false", "property2=value2"); + this.context.register(MultiplePropertiesRequiredConfiguration.class); + this.context.refresh(); + assertFalse(this.context.containsBean("foo")); + } + + @Test + public void propertyValueEqualsFALSE() { + EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), + "property1=FALSE", "property2=value2"); + this.context.register(MultiplePropertiesRequiredConfiguration.class); + this.context.refresh(); + assertFalse(this.context.containsBean("foo")); + } + + @Test + public void relaxedName() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), + "spring.theRelaxedProperty=value1"); + this.context.register(RelaxedPropertiesRequiredConfiguration.class); + this.context.refresh(); + assertTrue(this.context.containsBean("foo")); + } + + @Test + public void nonRelaxedName() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context.getEnvironment(), + "theRelaxedProperty=value1"); + this.context.register(NonRelaxedPropertiesRequiredConfiguration.class); + this.context.refresh(); + assertFalse(this.context.containsBean("foo")); } @Configuration @@ -84,4 +99,26 @@ public class ConditionalOnPropertyTests { } + @Configuration + @ConditionalOnProperty(prefix = "spring.", value = "the-relaxed-property") + protected static class RelaxedPropertiesRequiredConfiguration { + + @Bean + public String foo() { + return "foo"; + } + + } + + @Configuration + @ConditionalOnProperty(value = "the-relaxed-property", relaxedNames = false) + protected static class NonRelaxedPropertiesRequiredConfiguration { + + @Bean + public String foo() { + return "foo"; + } + + } + }