Brett Slocum
Brett Slocum

Reputation: 390

When using Dependency Injection, how do I ignore missing properties?

I'm trying to make my application backwards compatible to at least one previous version. The biggest issue I'm having is expected properties that don't exist in the old properties file.

For instance, let's say the old properties file looks like this:

prop.old=some text

The new properties file looks like this:

prop.old=some text
prop.new=some new text

And the relevant section of the new app-context.xml looks like this:

<beans:bean id="myClass" class="com.mycompany.MyClass">
    <beans:property name="oldThing" value="${prop.old}" />
    <beans:property name="newThing" value="${prop.new}" />
</beans:bean>

Obviously, this will blow up at runtime. Is there a way to check if the property exists and, if it doesn't, using an empty string instead?

Upvotes: 3

Views: 2650

Answers (2)

ericbado
ericbado

Reputation: 203

It is tricky because if you try to ignore the missing properties, you can't tell the missing ones are compulsory or optional. So I prefer a programmatic way to do it.

First, have a base class to access any properties file:

public abstract class ClasspathProperties {

    private final Environment environment;

    public ClasspathProperties(final Environment environment, final String propertiesLocation) {
        try {
            final PropertySource<?> propertySource = new ResourcePropertySource(propertiesLocation);
            verifyProperties(propertySource);
            ((ConfigurableEnvironment) environment).getPropertySources().addFirst(propertySource);
            this.environment = environment;
        } catch (final IOException e) {
            throw new IllegalStateException("reading properties from location " + propertiesLocation + " failed", e);
        }
    }

    public Environment getEnvironment() {
        return environment;
    }

    protected abstract void verifyProperties(PropertySource<?> propertySource);

    protected void verifyPropertyExistence(final PropertySource<?> propertySource, final String propertyName,
            final String propertyDescription) {
        final Object propertyValue = propertySource.getProperty(propertyName);
        if (propertyValue == null || "".equals(propertyValue)) {
            throw new IllegalStateException(propertyDescription + " is not set");
        }
    }

}

Then you can have one to read specified properties file and validate before setting the properties:

public class ClasspathDatabaseProperties extends ClasspathProperties implements DatabaseProperties {

    public ClasspathDatabaseProperties(final Environment environment) {
        this(environment, "classpath:/config/db-config.properties");
    }

    public ClasspathDatabaseProperties(final Environment environment, final String propertiesLocation) {
        super(environment, propertiesLocation);
    }

    @Override
    protected void verifyProperties(final PropertySource<?> propertySource) {
        verifyPropertyExistence(propertySource, "mysql.host", "MySQL DB host");
        verifyPropertyExistence(propertySource, "mysql.port", "MySQL DB port");
        verifyPropertyExistence(propertySource, "mysql.database", "MySQL DB DB name");
        verifyPropertyExistence(propertySource, "mysql.username", "MySQL DB username");
        verifyPropertyExistence(propertySource, "mysql.password", "MySQL DB password");
    }

    @Override
    public String getHost() {
        return getEnvironment().getProperty("mysql.host");
    }

    @Override
    public int getPortNumber() {
        return getEnvironment().getProperty("mysql.port", Integer.class);
    }

    @Override
    public String getDatabase() {
        return getEnvironment().getProperty("mysql.database");
    }

    @Override
    public String getUsername() {
        return getEnvironment().getProperty("mysql.username");
    }

    @Override
    public String getPassword() {
        return getEnvironment().getProperty("mysql.password");
    }

}

getProperty(String key) returns null if the key cannot be resolved.

Upvotes: 0

Jose Luis Martin
Jose Luis Martin

Reputation: 10709

Since 3.0 you can use ignore-unresolvable=true in PropertyPlaceholderConfigurer

<context:property-placeholder ignore-unresolvable="true" />

Upvotes: 2

Related Questions