title: Spring 4 @Conditional: Environment properties not available unless @PropertySource is used
body: <p><strong>Problem:</strong></p>
  
  <p>When using <code>@Conditional</code> bean definitions within <code>@Configuration</code> classes, properties from external sources, e. g. files, are not available in the <code>Environment</code> when <code>Condition#matches</code> is evaluated - <strong>unless</strong> <code>@PropertySource</code> is used. Using <code>ConfigurationCondition</code> instead of <code>Condition</code> doesn't make a difference, no matter which <code>ConfigurationPhase</code> is used.</p>
  
  <p>Since I also have the requirement to use wildcards for the names of my properties files, using <code>@PropertySource</code> is not an option, since it requires the locations to be absolute.  Spring Boot is completely off the table, so <code>@ConditionalOnProperty</code> is not an option either. This leaves me with defining a <code>PropertySourcesPlaceholderConfigurer</code> bean as the only remaining viable option.</p>
  
  <p><strong>Question:</strong></p>
  
  <p>Is there any way to define beans depending on the presence, absence or value of properties in the <code>Environment</code> using plain Spring mechanisms (not boot, and not some other hacky way) while also specifying property locations with wildcards and if so, what would need to be done?</p>
  
  <p><strong>Example:</strong></p>
  
  <p>In the following <code>JUnit</code> test, I expect a bean named <code>bean</code> to be available, iff the property <code>key</code> is available (i. e. not <code>null</code>) in the <code>Environment</code> during the evaluation of the <code>matches</code> method in the <code>PropertyCondition</code>. This is not the case, thus the test fails.</p>
  
  <pre class="lang-java prettyprint-override"><code>@RunWith(SpringJUnit4ClassRunner.class)
  @ContextConfiguration(classes = { ConditionTest.ConditionTestConfiguration.class })
  public class ConditionTest {
  
    private static final String PROPERTIES_LOCATION = "test.properties";
    private static final String BEAN_NAME = "bean";
  
    @Autowired
    private ApplicationContext applicationContext;
  
    @Test
    public void testBeanNotNull() {
      assertNotNull(applicationContext.getBean(BEAN_NAME));
    }
  
    @Configuration
    static class ConditionTestConfiguration {
  
      @Bean
      public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        propertySourcesPlaceholderConfigurer.setLocation(new ClassPathResource(PROPERTIES_LOCATION));
        return propertySourcesPlaceholderConfigurer;
      }
  
      @Bean
      @Conditional(PropertyCondition.class)
      public Object bean() {
        return BEAN_NAME;
      }
  
    }
  
    static class PropertyCondition implements ConfigurationCondition {
  
      private static final String PROPERTY_KEY = "key";
  
      @Override
      public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty(PROPERTY_KEY) != null;
      }
  
      @Override
      public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.REGISTER_BEAN;
      }
  
    }
  
  }
  </code></pre>
  
  <p>Once I add an <code>@PropertySource</code> annotation to the <code>ConditionTestConfiguration</code> like this:</p>
  
  <pre class="lang-java prettyprint-override"><code>  @Configuration
    @PropertySource("classpath:test.properties")
    static class ConditionTestConfiguration 
  </code></pre>
  
  <p>the property <code>key</code> is available, thus the <code>PropertyCondition#matches</code> method evaluates to true, thus <code>bean</code> is available in the <code>ApplicationContext</code> and the test passes.</p>
  
  <p><strong>Additional Information:</strong></p>
  
  <ul>
  <li>A file called <code>test.properties</code> containing <code>key=value</code> exists in the classpath</li>
  <li>I used a <code>ConfigurationCondition</code> with <code>ConfigurationPhase.REGISTER_BEAN</code>, just to show that it doesn't change the behaviour for the better</li>
  <li>Package declaration and import statements are omitted for brevity</li>
  </ul>