2

I have a class that configures database specific properties from environment. It looks like

@Configuration
@Profile("default")
public class MySqlDatabaseConfig extends JpaCommonConfig {
    @Value("${database_url:jdbc:mysql://localhost:3306/pryme?createDatabaseIfNotExist=true }")
    private String databaseUrl;

    @Value("${database_user:root}")
    private String databaseUser;

    @Value("${database_password:\"\"}")
    private String databasePassword;

    @Value("${database_driverClassName:com.mysql.jdbc.Driver}")
    private String databaseDriverClass;


    private static final Logger LOGGER = LoggerFactory.getLogger(MySqlDatabaseConfig.class);

    @Override
    public DataSource dataSource() {
        final BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(getDriverClassName());
        dataSource.setUrl(getUrl());
        dataSource.setUsername(getUser());
        if (!getPassword().trim().isEmpty()) {
            dataSource.setPassword(getPassword());
        }

        LOGGER.debug("DriverClass={}, URL={}, User={}", getDriverClassName(), getUrl(), getUser());
        return dataSource;
    }

    @Override
    public String getUrl() {
        return databaseUrl;
    }

    @Override
    public String getUser() {
        return databaseUser;
    }

    @Override
    public String getPassword() {
        return databasePassword;
    }

    @Override
    public String getDriverClassName() {
        return databaseDriverClass;
    }

    @Override
    protected Class<? extends Dialect> getDatabaseDialect() {
        return MySQL5InnoDBDialect.class;
    }
}

When my tests run, I see failures as

[INFO] [talledLocalContainer] Jun 12, 2014 8:47:45 AM org.apache.catalina.core.StandardContext listenerStart
[INFO] [talledLocalContainer]   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
[INFO] [talledLocalContainer]   ... 25 common frames omitted
[INFO] [talledLocalContainer] Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '${database_driverClassName:com.mysql.jdbc.Driver}'
[INFO] [talledLocalContainer] SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
[INFO] [talledLocalContainer]   at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1429) ~[commons-dbcp-1.4.jar:1.4]
[INFO] [talledLocalContainer]   at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371) ~[commons-dbcp-1.4.jar:1.4]
[INFO] [talledLocalContainer] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is liquibase.exception.DatabaseException: org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '${database_driverClassName:com.mysql.jdbc.Driver}'
[INFO] [talledLocalContainer]   at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) ~[commons-dbcp-1.4.jar:1.4]
[INFO] [talledLocalContainer]   at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:296) ~[liquibase-core-3.1.1.jar:na]
[INFO] [talledLocalContainer]   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
[INFO] [talledLocalContainer]   ... 27 common frames omitted
[INFO] [talledLocalContainer] Caused by: java.lang.ClassNotFoundException: ${database_driverClassName:com.mysql.jdbc.Driver}

seems as if @Value annotation is not dereferencing values

What is that I miss here?

1
  • How are you getting that database_driverClassName property into the Spring context? Commented Jun 12, 2014 at 16:02

3 Answers 3

1

You should put the values in an application.properties file like:

database_url=jdbc:mysql://localhost:3306/pryme?createDatabaseIfNotExist=true
database_user=root
# more values...

Now, if you can create an application config that fetches the value from the .properties file (the name is not important as long as it matches the .properties file above).

@Configuration
@PropertySource(value = "classpath:application.properties")
public class AppConfig{

@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

From this point, the @Value annotation will resolve the actual values if you specify the keys in the .properties file:

@Value("${database_url}")
String databaseUrl;

@Value("${database_user}")
String databaseUser;
Sign up to request clarification or add additional context in comments.

Comments

1

You need a PropertySource and PropertySourcesPlaceholderConfigurer.

e.g.:

@Configuration
@PropertySource(value = { "classpath:application.properties" })
...


@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

Comments

0

You can also use the @Resource annotation like this :

@Configuration
@PropertySource("classpath:application.properties")
...

@Resource
private Environment env;


dataSource.setUrl(env.getRequiredProperty("dataSource.url"));

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.