Rename some ConditionalOnProperty attributes

Rename the newly introduced @ConditionalOnProperty `match` and
`defaultMatch` attributes to `havingValue` and `matchIfMissing`.

Also added a new `name` attribute as an alternative to `value` to
aid readability.

Closes gh-1000
This commit is contained in:
Phillip Webb 2014-07-28 23:17:34 -07:00
parent 6825a7b42e
commit 8e0b3dd00a
19 changed files with 220 additions and 169 deletions

View File

@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.Advice;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@ -40,19 +39,18 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
*/
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(value = "spring.aop.auto", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(value = "spring.aop.proxyTargetClass", match = "false", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnExpression("${spring.aop.proxyTargetClass:false}")
@ConditionalOnProperty(value = "spring.aop.proxyTargetClass", match = "true", defaultMatch = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
public static class CglibAutoProxyConfiguration {
}

View File

@ -78,7 +78,7 @@ public class BatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.batch.job.enabled", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.batch.job", name = "enabled", havingValue = "true", matchIfMissing = true)
public JobLauncherCommandLineRunner jobLauncherCommandLineRunner(
JobLauncher jobLauncher, JobExplorer jobExplorer) {
JobLauncherCommandLineRunner runner = new JobLauncherCommandLineRunner(

View File

@ -25,66 +25,56 @@ import org.springframework.context.annotation.Conditional;
import org.springframework.core.env.Environment;
/**
* {@link Conditional} that checks if the specified properties
* have the requested matching value. By default the properties
* must be present in the {@link Environment} ant <strong>not</strong>
* equal to {@code false}. The {@link #match()} and {@link #defaultMatch()}
* attributes allow to further customize the condition.
* {@link Conditional} that checks if the specified properties have a specific value. By
* default the properties must be present in the {@link Environment} and
* <strong>not</strong> equal to {@code false}. The {@link #havingValue()} and
* {@link #matchIfMissing()} attributes allow further customizations.
*
* <p>The {@link #match} attribute provides the value that the property
* should have. The {@link #defaultMatch()} flag specifies if the
* condition <strong>also</strong> matches if the property is not present
* at all.
*
* <p>The table below defines when a condition match according to the
* property value and the {@link #match()} value
* <p>
* The {@link #havingValue} attribute can be used to specify the value that the property
* should have. The table below shows when a condition matches according to the property
* value and the {@link #havingValue()} attribute:
*
* <p>
* <table border="1">
* <th>
* <td>no {@code match} value</td>
* <td>{@code true}</td>
* <td>{@code false}</td>
* <td>{@code foo}</td>
* </th>
* <tr>
* <td>not set ({@code defaultMatch = false})</td>
* <td>no</td>
* <td>no</td>
* <td>no</td>
* <td>no</td>
* <th>Property Value</th>
* <th>{@code havingValue=""}</th>
* <th>{@code havingValue="true"}</th>
* <th>{@code havingValue="false"}</th>
* <th>{@code havingValue="foo"}</th>
* </tr>
* <tr>
* <td>not set ({@code defaultMatch = true})</td>
* <td>yes</td>
* <td>yes</td>
* <td>yes</td>
* <td>yes</td>
* <td>{@code "true"}</td>
* <td>yes</td>
* <td>yes</td>
* <td>no</td>
* <td>no</td>
* </tr>
* <tr>
* <td>{@code true}</td>
* <td>yes</td>
* <td>yes</td>
* <td>no</td>
* <td>no</td>
* <td>{@code "false"}</td>
* <td>no</td>
* <td>no</td>
* <td>yes</td>
* <td>no</td>
* </tr>
* <tr>
* <td>{@code false}</td>
* <td>no</td>
* <td>no</td>
* <td>yes</td>
* <td>no</td>
* </tr>
* <tr>
* <td>{@code foo}</td>
* <td>yes</td>
* <td>no</td>
* <td>no</td>
* <td>yes</td>
* <td>{@code "foo"}</td>
* <td>yes</td>
* <td>no</td>
* <td>no</td>
* <td>yes</td>
* </tr>
* </table>
*
* <p>
* If the property is not contained in the {@link Environment} at all, the
* {@link #matchIfMissing()} attribute is consulted. By default missing attributes do not
* match.
*
* @author Maciej Walkowiak
* @author Stephane Nicoll
* @author Phillip Webb
* @since 1.1.0
*/
@Conditional(OnPropertyCondition.class)
@ -93,38 +83,38 @@ import org.springframework.core.env.Environment;
public @interface ConditionalOnProperty {
/**
* A prefix that should be applied to each property.
* <p>Defaults to no prefix. The prefix automatically
* ends with a dot if not specified.
* Alias for {@link #name()}.
*/
String[] value() default {};
/**
* A prefix that should be applied to each property. The prefix automatically ends
* with a dot if not specified.
*/
String prefix() default "";
/**
* One or more properties to validate against the
* {@link #match} value. If a prefix has been defined, it
* is applied to compute the full key of each property. For
* instance if the prefix is {@code app.config} and one
* value is {@code my-value}, the fully key would be
* The name of the properties to test.If a prefix has been defined, it is applied to
* compute the full key of each property. For instance if the prefix is
* {@code app.config} and one value is {@code my-value}, the fully key would be
* {@code app.config.my-value}
* <p>Use the dashed notation to specify each property, that
* is all lower case with a "-" to separate words (e.g.
* {@code my-long-property}).
* @return the property names
* <p>
* Use the dashed notation to specify each property, that is all lower case with a "-"
* to separate words (e.g. {@code my-long-property}).
*/
String[] value();
String[] name() default {};
/**
* The string representation of the expected value for the
* properties. If not specified, the property must
* <strong>not</strong> be equals to {@code false}
* The string representation of the expected value for the properties. If not
* specified, the property must <strong>not</strong> be equals to {@code false}
*/
String match() default "";
String havingValue() default "";
/**
* Specify if the condition should match if the property is not set.
* Defaults to {@code false}
* Specify if the condition should match if the property is not set. Defaults to
* {@code false}
*/
boolean defaultMatch() default false;
boolean matchIfMissing() default false;
/**
* If relaxed names should be checked. Defaults to {@code true}.

View File

@ -23,8 +23,10 @@ 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.annotation.AnnotationAttributes;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@ -42,41 +44,35 @@ class OnPropertyCondition extends SpringBootCondition {
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(
ConditionalOnProperty.class.getName());
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(metadata
.getAnnotationAttributes(ConditionalOnProperty.class.getName()));
String prefix = getPrefix(annotationAttributes);
String expectedValue = getExpectedValue(annotationAttributes);
String[] names = (String[]) annotationAttributes.get("value");
boolean relaxedNames = (Boolean) annotationAttributes.get("relaxedNames");
boolean matchDefault = (Boolean) annotationAttributes.get("defaultMatch");
List<String> missingProperties = new ArrayList<String>();
List<String> nonMatchingProperties = new ArrayList<String>();
String prefix = annotationAttributes.getString("prefix").trim();
if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) {
prefix = prefix + ".";
}
String havingValue = annotationAttributes.getString("havingValue");
String[] names = getNames(annotationAttributes);
boolean relaxedNames = annotationAttributes.getBoolean("relaxedNames");
boolean matchIfMissing = annotationAttributes.getBoolean("matchIfMissing");
PropertyResolver resolver = context.getEnvironment();
if (relaxedNames) {
resolver = new RelaxedPropertyResolver(resolver, prefix);
prefix = "";
}
List<String> missingProperties = new ArrayList<String>();
List<String> nonMatchingProperties = new ArrayList<String>();
for (String name : names) {
name = prefix + name;
boolean hasProperty = resolver.containsProperty(name);
if (!hasProperty) { // property not set
if (!matchDefault) { // property is mandatory
missingProperties.add(name);
String key = (relaxedNames ? name : prefix + name);
if (resolver.containsProperty(key)) {
if (!isMatch(resolver.getProperty(key), havingValue)) {
nonMatchingProperties.add(name);
}
}
else {
String actualValue = resolver.getProperty(name);
if (expectedValue == null) {
if ("false".equalsIgnoreCase(actualValue)) {
nonMatchingProperties.add(name);
}
}
else if (!expectedValue.equalsIgnoreCase(actualValue)) {
nonMatchingProperties.add(name);
if (!matchIfMissing) {
missingProperties.add(name);
}
}
}
@ -85,42 +81,45 @@ class OnPropertyCondition extends SpringBootCondition {
return ConditionOutcome.match();
}
StringBuilder sb = new StringBuilder("@ConditionalOnProperty ");
if (!matchDefault && !missingProperties.isEmpty()) {
sb.append("missing required properties ")
.append(StringUtils.arrayToCommaDelimitedString(missingProperties.toArray()))
.append(" ");
StringBuilder message = new StringBuilder("@ConditionalOnProperty ");
if (!missingProperties.isEmpty()) {
message.append("missing required properties "
+ expandNames(prefix, missingProperties) + " ");
}
if (!nonMatchingProperties.isEmpty()) {
String expected = expectedValue == null ? "!false" : expectedValue;
sb.append("expected '").append(expected).append("' for properties: ")
.append(StringUtils.arrayToCommaDelimitedString(nonMatchingProperties.toArray()));
String expected = havingValue == null ? "!false" : havingValue;
message.append("expected '").append(expected).append("' for properties ")
.append(expandNames(prefix, nonMatchingProperties));
}
return ConditionOutcome.noMatch(sb.toString());
return ConditionOutcome.noMatch(message.toString());
}
/**
* Return the prefix to use or an empty String if it's not set.
* <p>Add a dot at the end if it is not present already.
*/
private static String getPrefix(Map<String, Object> annotationAttributes) {
String prefix = ((String) annotationAttributes.get("prefix")).trim();
if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) {
prefix = prefix + ".";
}
return prefix;
private String[] getNames(Map<String, Object> annotationAttributes) {
String[] value = (String[]) annotationAttributes.get("value");
String[] name = (String[]) annotationAttributes.get("name");
Assert.state(value.length > 0 || name.length > 0,
"The name or value attribute of @ConditionalOnProperty must be specified");
Assert.state(value.length == 0 || name.length == 0,
"The name and value attributes of @ConditionalOnProperty are exclusive");
return (value.length > 0 ? value : name);
}
/**
* Return the expected value to match against or {@code null} if no
* match value is set.
*/
private static String getExpectedValue(Map<String, Object> annotationAttributes) {
String match = (String) annotationAttributes.get("match");
if (StringUtils.hasText(match)) {
return match;
private boolean isMatch(String value, String requiredValue) {
if (StringUtils.hasLength(requiredValue)) {
return requiredValue.equalsIgnoreCase(value);
}
return null;
return !"false".equalsIgnoreCase(value);
}
private String expandNames(String prefix, List<String> names) {
StringBuffer expanded = new StringBuffer();
for (String name : names) {
expanded.append(expanded.length() == 0 ? "" : ", ");
expanded.append(prefix);
expanded.append(name);
}
return expanded.toString();
}
}

View File

@ -38,8 +38,7 @@ import org.springframework.data.repository.core.support.RepositoryFactoryBeanSup
*/
@Configuration
@ConditionalOnClass({ Client.class, ElasticsearchRepository.class })
@ConditionalOnProperty(value = "spring.data.elasticsearch.repositories.enabled",
match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.data.elasticsearch.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnMissingBean(RepositoryFactoryBeanSupport.class)
@Import(ElasticsearchRepositoriesAutoConfigureRegistrar.class)
public class ElasticsearchRepositoriesAutoConfiguration {

View File

@ -59,7 +59,7 @@ import org.springframework.data.web.config.EnableSpringDataWebSupport;
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({ RepositoryFactoryBeanSupport.class,
JpaRepositoryConfigExtension.class })
@ConditionalOnProperty(value = "spring.data.jpa.repositories.enabled", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@Import(JpaRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
public class JpaRepositoriesAutoConfiguration {

View File

@ -56,7 +56,7 @@ import com.mongodb.Mongo;
@ConditionalOnClass({ Mongo.class, MongoRepository.class })
@ConditionalOnMissingBean({ RepositoryFactoryBeanSupport.class,
MongoRepositoryConfigurationExtension.class })
@ConditionalOnProperty(value = "spring.data.mongo.repositories.enabled", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.data.mongo.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@Import(MongoRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter(MongoAutoConfiguration.class)
public class MongoRepositoriesAutoConfiguration {

View File

@ -47,7 +47,7 @@ import org.springframework.data.solr.repository.config.SolrRepositoryConfigExten
@ConditionalOnClass({ SolrServer.class, SolrRepository.class })
@ConditionalOnMissingBean({ RepositoryFactoryBeanSupport.class,
SolrRepositoryConfigExtension.class })
@ConditionalOnProperty(value = "spring.data.solr.repositories.enabled", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.data.solr.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@Import(SolrRepositoriesAutoConfigureRegistrar.class)
public class SolrRepositoriesAutoConfiguration {

View File

@ -51,7 +51,7 @@ public class IntegrationAutoConfiguration {
@Configuration
@ConditionalOnClass(EnableIntegrationMBeanExport.class)
@ConditionalOnMissingBean(value = IntegrationMBeanExporter.class, search = SearchStrategy.CURRENT)
@ConditionalOnProperty(value = "spring.jmx.enabled", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableIntegrationMBeanExport(defaultDomain = "${spring.jmx.default_domain:}", server = "${spring.jmx.server:mbeanServer}")
protected static class IntegrationJmxConfiguration {
}

View File

@ -53,7 +53,7 @@ import org.springframework.util.ClassUtils;
*/
@Configuration
@ConditionalOnClass({ MBeanExporter.class })
@ConditionalOnProperty(value = "spring.jmx.enabled", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true", matchIfMissing = true)
public class JmxAutoConfiguration {
@Autowired

View File

@ -88,7 +88,7 @@ public class DeviceDelegatingViewResolverAutoConfiguration {
@Configuration
@EnableConfigurationProperties(DeviceDelegatingViewResolverProperties.class)
@ConditionalOnMissingBean(name = "deviceDelegatingViewResolver")
@ConditionalOnProperty(value = "spring.mobile.devicedelegatingviewresolver.enabled", match = "true", defaultMatch = false)
@ConditionalOnProperty(prefix = "spring.mobile.devicedelegatingviewresolver", name = "enabled", havingValue = "true", matchIfMissing = false)
protected static class DeviceDelegatingViewResolverConfiguration {
@Configuration

View File

@ -47,7 +47,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
@ConditionalOnClass({ SitePreferenceHandlerInterceptor.class,
SitePreferenceHandlerMethodArgumentResolver.class })
@AutoConfigureAfter(DeviceResolverAutoConfiguration.class)
@ConditionalOnProperty(value ="spring.mobile.sitepreference.enabled", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.mobile.sitepreference", name = "enabled", havingValue = "true", matchIfMissing = true)
public class SitePreferenceAutoConfiguration {
@Configuration

View File

@ -136,7 +136,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
@ConditionalOnWebApplication
@ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class,
OpenEntityManagerInViewFilter.class })
@ConditionalOnProperty(prefix = "spring.jpa", value = "openInView", match = "true", defaultMatch = true)
@ConditionalOnProperty(prefix = "spring.jpa", name = "open-in-view", havingValue = "true", matchIfMissing = true)
protected static class JpaWebConfiguration extends WebMvcConfigurerAdapter {
@Override

View File

@ -50,7 +50,7 @@ import org.springframework.web.servlet.View;
*/
@Configuration
@ConditionalOnClass({ SocialConfigurerAdapter.class, FacebookConnectionFactory.class })
@ConditionalOnProperty(prefix = "spring.social.facebook.", value = "app-id")
@ConditionalOnProperty(prefix = "spring.social.facebook", name = "app-id")
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class FacebookAutoConfiguration {
@ -75,7 +75,7 @@ public class FacebookAutoConfiguration {
}
@Bean(name = { "connect/facebookConnect", "connect/facebookConnected" })
@ConditionalOnProperty(prefix = "spring.social.", value = "auto-connection-views")
@ConditionalOnProperty(prefix = "spring.social", name = "auto-connection-views")
public View facebookConnectView() {
return new GenericConnectionStatusView("facebook", "Facebook");
}

View File

@ -49,7 +49,7 @@ import org.springframework.web.servlet.View;
*/
@Configuration
@ConditionalOnClass({ SocialConfigurerAdapter.class, LinkedInConnectionFactory.class })
@ConditionalOnProperty(prefix = "spring.social.linkedin.", value = "app-id")
@ConditionalOnProperty(prefix = "spring.social.linkedin", name = "app-id")
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class LinkedInAutoConfiguration {
@ -74,7 +74,7 @@ public class LinkedInAutoConfiguration {
}
@Bean(name = { "connect/linkedinConnect", "connect/linkedinConnected" })
@ConditionalOnProperty(prefix = "spring.social.", value = "auto-connection-views")
@ConditionalOnProperty(prefix = "spring.social", name = "auto-connection-views")
public View linkedInConnectView() {
return new GenericConnectionStatusView("linkedin", "LinkedIn");
}

View File

@ -99,7 +99,7 @@ public class SocialWebAutoConfiguration {
@Bean
@ConditionalOnMissingBean(BeanNameViewResolver.class)
@ConditionalOnProperty(prefix = "spring.social.", value = "auto-connection-views")
@ConditionalOnProperty(prefix = "spring.social", name = "auto-connection-views")
public ViewResolver beanNameViewResolver() {
BeanNameViewResolver viewResolver = new BeanNameViewResolver();
viewResolver.setOrder(Integer.MIN_VALUE);

View File

@ -50,7 +50,7 @@ import org.springframework.web.servlet.View;
*/
@Configuration
@ConditionalOnClass({ SocialConfigurerAdapter.class, TwitterConnectionFactory.class })
@ConditionalOnProperty(prefix = "spring.social.twitter.", value = "app-id")
@ConditionalOnProperty(prefix = "spring.social.twitter", name = "app-id")
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class TwitterAutoConfiguration {
@ -79,7 +79,7 @@ public class TwitterAutoConfiguration {
}
@Bean(name = { "connect/twitterConnect", "connect/twitterConnected" })
@ConditionalOnProperty(prefix = "spring.social.", value = "auto-connection-views")
@ConditionalOnProperty(prefix = "spring.social", name = "auto-connection-views")
public View twitterConnectView() {
return new GenericConnectionStatusView("twitter", "Twitter");
}

View File

@ -197,14 +197,14 @@ public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean(LocaleResolver.class)
@ConditionalOnProperty(prefix = "spring.mvc.", value = "locale")
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
return new FixedLocaleResolver(
StringUtils.parseLocaleString(this.mvcProperties.getLocale()));
}
@Bean
@ConditionalOnProperty(prefix = "spring.mvc.", value = "date-format")
@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());
}

View File

@ -17,23 +17,31 @@
package org.springframework.boot.autoconfigure.condition;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
/**
* Tests for {@link ConditionalOnProperty}.
*
* @author Maciej Walkowiak
* @author Stephane Nicoll
* @author Phillip Webb
*/
public class ConditionalOnPropertyTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
@After
@ -45,29 +53,28 @@ public class ConditionalOnPropertyTests {
@Test
public void allPropertiesAreDefined() {
load(MultiplePropertiesRequiredConfiguration.class,
"property1=value1", "property2=value2");
load(MultiplePropertiesRequiredConfiguration.class, "property1=value1",
"property2=value2");
assertTrue(this.context.containsBean("foo"));
}
@Test
public void notAllPropertiesAreDefined() {
load(MultiplePropertiesRequiredConfiguration.class,
"property1=value1");
load(MultiplePropertiesRequiredConfiguration.class, "property1=value1");
assertFalse(this.context.containsBean("foo"));
}
@Test
public void propertyValueEqualsFalse() {
load(MultiplePropertiesRequiredConfiguration.class,
"property1=false", "property2=value2");
load(MultiplePropertiesRequiredConfiguration.class, "property1=false",
"property2=value2");
assertFalse(this.context.containsBean("foo"));
}
@Test
public void propertyValueEqualsFALSE() {
load(MultiplePropertiesRequiredConfiguration.class,
"property1=FALSE", "property2=value2");
load(MultiplePropertiesRequiredConfiguration.class, "property1=FALSE",
"property2=value2");
assertFalse(this.context.containsBean("foo"));
}
@ -87,12 +94,12 @@ public class ConditionalOnPropertyTests {
@Test
public void nonRelaxedName() throws Exception {
load(NonRelaxedPropertiesRequiredConfiguration.class,
"theRelaxedProperty=value1");
load(NonRelaxedPropertiesRequiredConfiguration.class, "theRelaxedProperty=value1");
assertFalse(this.context.containsBean("foo"));
}
@Test // Enabled by default
@Test
// Enabled by default
public void enabledIfNotConfiguredOtherwise() {
load(EnabledIfNotConfiguredOtherwiseConfig.class);
assertTrue(this.context.containsBean("foo"));
@ -110,7 +117,8 @@ public class ConditionalOnPropertyTests {
assertFalse(this.context.containsBean("foo"));
}
@Test // Disabled by default
@Test
// Disabled by default
public void disableIfNotConfiguredOtherwise() {
load(DisabledIfNotConfiguredOtherwiseConfig.class);
assertFalse(this.context.containsBean("foo"));
@ -184,7 +192,8 @@ public class ConditionalOnPropertyTests {
@Test
public void multiValuesAllSet() {
load(MultiValuesConfig.class, "simple.my-property:bar", "simple.my-another-property:bar");
load(MultiValuesConfig.class, "simple.my-property:bar",
"simple.my-another-property:bar");
assertTrue(this.context.containsBean("foo"));
}
@ -194,6 +203,28 @@ public class ConditionalOnPropertyTests {
assertFalse(this.context.containsBean("foo"));
}
@Test
public void usingValueAttribute() throws Exception {
load(ValueAttribute.class, "some.property");
assertTrue(this.context.containsBean("foo"));
}
@Test
public void nameOrValueMustBeSpecified() throws Exception {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectCause(hasMessage(containsString("The name or "
+ "value attribute of @ConditionalOnProperty must be specified")));
load(NoNameOrValueAttribute.class, "some.property");
}
@Test
public void nameAndValueMustNotBeSpecified() throws Exception {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectCause(hasMessage(containsString("The name and "
+ "value attributes of @ConditionalOnProperty are exclusive")));
load(NameAndValueAttribute.class, "some.property");
}
private void load(Class<?> config, String... environment) {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, environment);
@ -201,9 +232,8 @@ public class ConditionalOnPropertyTests {
this.context.refresh();
}
@Configuration
@ConditionalOnProperty({ "property1", "property2" })
@ConditionalOnProperty(name = { "property1", "property2" })
protected static class MultiplePropertiesRequiredConfiguration {
@Bean
@ -214,7 +244,7 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(prefix = "spring.", value = "the-relaxed-property")
@ConditionalOnProperty(prefix = "spring.", name = "the-relaxed-property")
protected static class RelaxedPropertiesRequiredConfiguration {
@Bean
@ -225,7 +255,7 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(prefix = "spring", value = "property")
@ConditionalOnProperty(prefix = "spring", name = "property")
protected static class RelaxedPropertiesRequiredConfigurationWithShortPrefix {
@Bean
@ -236,7 +266,7 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(value = "the-relaxed-property", relaxedNames = false)
@ConditionalOnProperty(name = "the-relaxed-property", relaxedNames = false)
protected static class NonRelaxedPropertiesRequiredConfiguration {
@Bean
@ -246,8 +276,9 @@ public class ConditionalOnPropertyTests {
}
@Configuration // ${simple.myProperty:true}
@ConditionalOnProperty(prefix = "simple", value = "my-property", match = "true", defaultMatch = true)
@Configuration
// i.e ${simple.myProperty:true}
@ConditionalOnProperty(prefix = "simple", name = "my-property", havingValue = "true", matchIfMissing = true)
static class EnabledIfNotConfiguredOtherwiseConfig {
@Bean
@ -257,8 +288,9 @@ public class ConditionalOnPropertyTests {
}
@Configuration // ${simple.myProperty:false}
@ConditionalOnProperty(prefix = "simple", value = "my-property", match = "true", defaultMatch = false)
@Configuration
// i.e ${simple.myProperty:false}
@ConditionalOnProperty(prefix = "simple", name = "my-property", havingValue = "true", matchIfMissing = false)
static class DisabledIfNotConfiguredOtherwiseConfig {
@Bean
@ -269,7 +301,7 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(prefix = "simple", value = "my-property", match = "bar")
@ConditionalOnProperty(prefix = "simple", name = "my-property", havingValue = "bar")
static class SimpleValueConfig {
@Bean
@ -280,7 +312,7 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(value = "simple.myProperty", match = "bar", defaultMatch = true)
@ConditionalOnProperty(name = "simple.myProperty", havingValue = "bar", matchIfMissing = true)
static class DefaultValueConfig {
@Bean
@ -291,7 +323,7 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(prefix = "simple", value = "my-property", match = "bar")
@ConditionalOnProperty(prefix = "simple", name = "my-property", havingValue = "bar")
static class PrefixValueConfig {
@Bean
@ -302,7 +334,7 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(prefix = "simple", value = "my-property", match = "bar", relaxedNames = false)
@ConditionalOnProperty(prefix = "simple", name = "my-property", havingValue = "bar", relaxedNames = false)
static class StrictNameConfig {
@Bean
@ -313,7 +345,8 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty(prefix = "simple", value = {"my-property", "my-another-property"}, match = "bar")
@ConditionalOnProperty(prefix = "simple", name = { "my-property",
"my-another-property" }, havingValue = "bar")
static class MultiValuesConfig {
@Bean
@ -323,4 +356,36 @@ public class ConditionalOnPropertyTests {
}
@Configuration
@ConditionalOnProperty("some.property")
protected static class ValueAttribute {
@Bean
public String foo() {
return "foo";
}
}
@Configuration
@ConditionalOnProperty
protected static class NoNameOrValueAttribute {
@Bean
public String foo() {
return "foo";
}
}
@Configuration
@ConditionalOnProperty(value = "x", name = "y")
protected static class NameAndValueAttribute {
@Bean
public String foo() {
return "foo";
}
}
}