diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyValue.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyValue.java
new file mode 100644
index 00000000000..8971b7e80d0
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyValue.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012-2014 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
+ *
+ * http://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.autoconfigure.condition;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Conditional;
+
+/**
+ * {@link Conditional} that only matches when a property
+ * has a given value.
+ *
+ *
If {@link #defaultMatch()} is {@code true} then the
+ * condition also matches if the property
+ * is not present at all.
+ *
+ * @author Stephane Nicoll
+ * @since 1.2.0
+ */
+@Conditional(OnPropertyValueCondition.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface ConditionalOnPropertyValue {
+
+ /**
+ * A prefix that should be applied to the property.
+ * Defaults to no prefix. The prefix automatically
+ * ends with a dot, it does not need to be added.
+ */
+ String prefix() default "";
+
+ /**
+ * The property to check. If a prefix has been defined, it
+ * is applied to compute the full key of the property. For
+ * instance if the prefix is {@code app.config} and this
+ * property is {@code my-value}, the fully key would be
+ * {@code app.config.my-value}
+ *
Use the dashed notation to specify the property, that
+ * is all lower case with a "-" to separate words (e.g.
+ * {@code my-long-property})
+ */
+ String property();
+
+ /**
+ * If relaxed names should be checked. Defaults to {@code true}.
+ */
+ boolean relaxedName() default true;
+
+ /**
+ * The string representation of the expected value for the property.
+ */
+ String value();
+
+ /**
+ * Specify if the condition should match if the property is not set.
+ * Defaults to {@code false}
+ *
This means that the specified {@link #value()} is actually
+ * the default one (i.e. the one that you expect if the property
+ * is not set).
+ */
+ boolean defaultMatch() default false;
+
+}
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 a729c490846..382599523cf 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
@@ -18,11 +18,10 @@ package org.springframework.boot.autoconfigure.condition;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
-import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
-import org.springframework.core.env.PropertyResolver;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;
@@ -31,6 +30,7 @@ import org.springframework.util.StringUtils;
*
* @author Maciej Walkowiak
* @author Phillip Webb
+ * @author Stephane Nicoll
* @see ConditionalOnProperty
* @since 1.1.0
*/
@@ -39,30 +39,20 @@ class OnPropertyCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
+ Map attributes = metadata
+ .getAnnotationAttributes(ConditionalOnProperty.class.getName());
- String prefix = ((String) metadata.getAnnotationAttributes(
- ConditionalOnProperty.class.getName()).get("prefix")).trim();
- if (!"".equals(prefix) && !prefix.endsWith(".")) {
- prefix = prefix + ".";
- }
- String[] names = (String[]) metadata.getAnnotationAttributes(
- ConditionalOnProperty.class.getName()).get("value");
- Boolean relaxedNames = (Boolean) metadata.getAnnotationAttributes(
- ConditionalOnProperty.class.getName()).get("relaxedNames");
+ String prefix = ((String) attributes.get("prefix")).trim();
+ Boolean relaxedNames = (Boolean) attributes.get("relaxedNames");
+ String[] names = (String[]) attributes.get("value");
+ PropertyHelper helper = new PropertyHelper(context.getEnvironment(), prefix, relaxedNames);
List missingProperties = new ArrayList();
-
- 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);
+ String propertyKey = helper.createPropertyKey(name);
+ if (!helper.getPropertyResolver().containsProperty(propertyKey)
+ || "false".equalsIgnoreCase(helper.getPropertyResolver().getProperty(propertyKey))) {
+ missingProperties.add(propertyKey);
}
}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyValueCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyValueCondition.java
new file mode 100644
index 00000000000..47d3224524e
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyValueCondition.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012-2014 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
+ *
+ * http://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.autoconfigure.condition;
+
+import java.util.Map;
+
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * {@link org.springframework.context.annotation.Condition Condition} that
+ * checks if a property has a given value. Can also be configured so that
+ * the value to check is the default, hence the absence of property matches
+ * as well.
+ *
+ * @author Stephane Nicoll
+ * @since 1.2.0
+ * @see ConditionalOnPropertyValue
+ */
+public class OnPropertyValueCondition extends SpringBootCondition {
+
+ @Override
+ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ Map attributes = metadata
+ .getAnnotationAttributes(ConditionalOnPropertyValue.class.getName());
+ String prefix = ((String) attributes.get("prefix")).trim();
+ String property = (String) attributes.get("property");
+ Boolean relaxedName = (Boolean) attributes.get("relaxedName");
+ String value = (String) attributes.get("value");
+ Boolean defaultMatch = (Boolean) attributes.get("defaultMatch");
+
+ PropertyHelper helper = new PropertyHelper(context.getEnvironment(), prefix, relaxedName);
+ String propertyKey = helper.createPropertyKey(property);
+ String actualValue = helper.getPropertyResolver().getProperty(propertyKey);
+
+ if (actualValue == null && defaultMatch) {
+ return ConditionOutcome.match("@ConditionalOnProperty no property '" + property
+ + "' is set, assuming default value '" + value + "'");
+ }
+ if (!value.equalsIgnoreCase(actualValue)) {
+ return ConditionOutcome.noMatch("@ConditionalOnProperty wrong value for property '"
+ + property + "': expected '" + value + "' but got '" + actualValue + "'");
+ }
+ return ConditionOutcome.match();
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/PropertyHelper.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/PropertyHelper.java
new file mode 100644
index 00000000000..ab44da3a63d
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/PropertyHelper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012-2014 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
+ *
+ * http://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.autoconfigure.condition;
+
+import org.springframework.boot.bind.RelaxedPropertyResolver;
+import org.springframework.core.env.PropertyResolver;
+import org.springframework.util.StringUtils;
+
+/**
+ * Helper for properties-related operations.
+ *
+ * @author Stephane Nicoll
+ * @since 1.2.0
+ */
+class PropertyHelper {
+
+ private final PropertyResolver propertyResolver;
+
+ private final String prefix;
+
+ private final boolean relaxedNames;
+
+ /**
+ * Create a new instance with the base {@link PropertyResolver} to use. If
+ * a prefix is set and does not end with a dot, it is added.
+ *
+ * @param propertyResolver the base property resolver
+ * @param prefix the prefix to lookup keys, if any
+ * @param relaxedNames if relaxed names should be checked
+ */
+ PropertyHelper(PropertyResolver propertyResolver, String prefix, boolean relaxedNames) {
+ this.prefix = cleanPrefix(prefix);
+ this.relaxedNames = relaxedNames;
+ if (relaxedNames) {
+ this.propertyResolver = new RelaxedPropertyResolver(propertyResolver, this.prefix);
+ }
+ else {
+ this.propertyResolver = propertyResolver;
+ }
+ }
+
+ /**
+ * Return the {@link PropertyResolver} to use.
+ */
+ public PropertyResolver getPropertyResolver() {
+ return propertyResolver;
+ }
+
+ /**
+ * Create the full property key for the specified property. Applies the
+ * configured prefix, if necessary.
+ */
+ public String createPropertyKey(String property) {
+ return (relaxedNames ? property : prefix + property);
+ }
+
+ private static String cleanPrefix(String prefix) {
+ return (StringUtils.hasText(prefix) && !prefix.endsWith(".") ? prefix + "." : prefix);
+ }
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyValueTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyValueTests.java
new file mode 100644
index 00000000000..da40bd39585
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyValueTests.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2012-2014 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
+ *
+ * http://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.autoconfigure.condition;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.Test;
+
+import org.springframework.boot.test.EnvironmentTestUtils;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Tests for {@link ConditionalOnPropertyValue}
+ *
+ * @author Stephane Nicoll
+ */
+public class ConditionalOnPropertyValueTests {
+
+ private AnnotationConfigApplicationContext context;
+
+ @After
+ public void tearDown() {
+ if (this.context != null) {
+ this.context.close();
+ }
+ }
+
+ @Test // Enabled by default
+ public void enabledIfNotConfiguredOtherwise() {
+ load(EnabledIfNotConfiguredOtherwiseConfig.class);
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void enabledIfNotConfiguredOtherwiseWithConfig() {
+ load(EnabledIfNotConfiguredOtherwiseConfig.class, "simple.myProperty:false");
+ assertFalse(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void enabledIfNotConfiguredOtherwiseWithConfigDifferentCase() {
+ load(EnabledIfNotConfiguredOtherwiseConfig.class, "simple.my-property:FALSE");
+ assertFalse(this.context.containsBean("foo"));
+ }
+
+ @Test // Disabled by default
+ public void disableIfNotConfiguredOtherwise() {
+ load(DisabledIfNotConfiguredOtherwiseConfig.class);
+ assertFalse(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void disableIfNotConfiguredOtherwiseWithConfig() {
+ load(DisabledIfNotConfiguredOtherwiseConfig.class, "simple.myProperty:true");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void disableIfNotConfiguredOtherwiseWithConfigDifferentCase() {
+ load(DisabledIfNotConfiguredOtherwiseConfig.class, "simple.myproperty:TrUe");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void simpleValueIsSet() {
+ load(SimpleValueConfig.class, "simple.myProperty:bar");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void caseInsensitive() {
+ load(SimpleValueConfig.class, "simple.myProperty:BaR");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void defaultValueIsSet() {
+ load(DefaultValueConfig.class, "simple.myProperty:bar");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void defaultValueIsNotSet() {
+ load(DefaultValueConfig.class);
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void defaultValueIsSetDifferentValue() {
+ load(DefaultValueConfig.class, "simple.myProperty:another");
+ assertFalse(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void prefix() {
+ load(PrefixValueConfig.class, "simple.myProperty:bar");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void relaxedEnabledByDefault() {
+ load(PrefixValueConfig.class, "simple.myProperty:bar");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void strictNameMatch() {
+ load(StrictNameConfig.class, "simple.my-property:bar");
+ assertTrue(this.context.containsBean("foo"));
+ }
+
+ @Test
+ public void strictNameNoMatch() {
+ load(StrictNameConfig.class, "simple.myProperty:bar");
+ assertFalse(this.context.containsBean("foo"));
+ }
+
+ private void load(Class> config, String... environment) {
+ this.context = new AnnotationConfigApplicationContext();
+ EnvironmentTestUtils.addEnvironment(this.context, environment);
+ this.context.register(config);
+ this.context.refresh();
+ }
+
+ @Configuration // ${simple.myProperty:true}
+ @ConditionalOnPropertyValue(prefix = "simple", property = "my-property", value = "true", defaultMatch = true)
+ static class EnabledIfNotConfiguredOtherwiseConfig {
+ @Bean
+ public String foo() {
+ return "foo";
+ }
+ }
+
+ @Configuration // ${simple.myProperty:false}
+ @ConditionalOnPropertyValue(prefix = "simple", property = "my-property", value = "true", defaultMatch = false)
+ static class DisabledIfNotConfiguredOtherwiseConfig {
+ @Bean
+ public String foo() {
+ return "foo";
+ }
+ }
+
+ @Configuration
+ @ConditionalOnPropertyValue(prefix = "simple", property = "my-property", value = "bar")
+ static class SimpleValueConfig {
+ @Bean
+ public String foo() {
+ return "foo";
+ }
+ }
+
+ @Configuration
+ @ConditionalOnPropertyValue(property = "simple.myProperty", value = "bar", defaultMatch = true)
+ static class DefaultValueConfig {
+ @Bean
+ public String foo() {
+ return "foo";
+ }
+ }
+
+ @Configuration
+ @ConditionalOnPropertyValue(prefix = "simple", property = "my-property", value = "bar")
+ static class PrefixValueConfig {
+ @Bean
+ public String foo() {
+ return "foo";
+ }
+ }
+
+ @Configuration
+ @ConditionalOnPropertyValue(prefix = "simple", property = "my-property", value = "bar", relaxedName = false)
+ static class StrictNameConfig {
+ @Bean
+ public String foo() {
+ return "foo";
+ }
+ }
+
+}