Optional @PropertySource location

java, spring, spring-annotations

Solution

Try the following. Create a `ApplicationContextInitializer`

In a Web Context: `ApplicationContextInitializer<ConfigurableWebApplicationContext>` and register it in the web.xml via:

<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>...ContextInitializer</param-value>
</context-param>

In the ContextInitializer you can add your property files via classpath and file system (haven't tried JNDI though).

  public void initialize(ConfigurableWebApplicationContext applicationContext) {
    String activeProfileName = null;
    String location = null;

    try {
      ConfigurableEnvironment environment = applicationContext.getEnvironment();
      String appconfigDir = environment.getProperty(APPCONFIG);
      if (appconfigDir == null ) {
        logger.error("missing property: " + APPCONFIG);
        appconfigDir = "/tmp";
      }
      String[] activeProfiles = environment.getActiveProfiles();

      for ( int i = 0; i < activeProfiles.length; i++ ) {
        activeProfileName = activeProfiles[i];
        MutablePropertySources propertySources = environment.getPropertySources();
        location = "file://" + appconfigDir + activeProfileName + ".properties";
        addPropertySource(applicationContext, activeProfileName,
                location, propertySources);
        location = "classpath:/" + activeProfileName + ".properties";
        addPropertySource(applicationContext, activeProfileName,
                          location, propertySources);
      }
      logger.debug("environment: '{}'", environment.getProperty("env"));

    } catch (IOException e) {
      logger.info("could not find properties file for active Spring profile '{}' (tried '{}')", activeProfileName, location);
      e.printStackTrace();
    }
  }

  private void addPropertySource(ConfigurableWebApplicationContext applicationContext, String activeProfileName,
                                 String location, MutablePropertySources propertySources) throws IOException {
    Resource resource = applicationContext.getResource(location);
    if ( resource.exists() ) {
      ResourcePropertySource propertySource = new ResourcePropertySource(location);
      propertySources.addLast(propertySource);
    } else {
      logger.info("could not find properties file for active Spring profile '{}' (tried '{}')", activeProfileName, location);
    }
  }

The code above tries to find a property file per active profile (see: How to set active spring 3.1 environment profile via a properites file and not via an env variable or system property)

Problem

I'm using Spring 3.2 in a web application and I'd like to have a `.properties` file within the classpath which contains default values. The user should be able to use JNDI to define a location where another `.properties` is stored which overrides the default values. The following works as long as the user has set the `configLocation` as JNDI property. ``` @Configuration @PropertySource({ "classpath:default.properties", "file:${java:comp/env/configLocation}/override.properties" }) public class AppConfig { } ``` However, the external overrides should be optional and so should the JNDI property. Currently I get an exception (`java.io.FileNotFoundException: comp\env\configLocation\app.properties (The system cannot find the path specified)` when the JNDI property is missing. How can I define optional `.properties` that are used only when the JNDI property (`configLocation`) is set? Is this even possible with `@PropertySource` or is there another solution?

Original source

Related problems