@PropertySource with AbstractJUnit4SpringContextTests and @ContextConfiguration
Hi all,
I am having a problem with eager bean creation. Lets assume we have the following @Configuration class:
Code:
@Configuration
@Profile("development")
@PropertySource("classpath:dev.properties")
public class DevelopmentRepositoryConfig {
@Autowired
@Qualifier("wurthshopDataSource")
private DataSource shopDataSource;
//more datasources - not needed for demonstration
@Autowired
Environment env;
@Bean(autowire = Autowire.BY_NAME)
public ComboPooledDataSource shopDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(env.getProperty("db.user"));
dataSource.setPassword(env.getProperty("db.password"));
dataSource.setJdbcUrl(env.getProperty("db.url"));
dataSource.setDriverClass(env.getProperty("db.driverClass.mysql"));
dataSource.setIdleConnectionTestPeriod(600);
dataSource.setPreferredTestQuery("SELECT 1;");
dataSource.setMinPoolSize(5);
dataSource.setMaxPoolSize(10);
dataSource.setMaxIdleTime(60);
return dataSource;
}
@Bean(autowire = Autowire.BY_NAME)
public SessionFactory wurthshopSessionFactory(){
Properties props = new Properties();
props.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
props.setProperty("hibernate.current_session_context_class", "org.springframework.orm.hibernate4.SpringSessionContext");
props.setProperty("hibernate.connection.driver_class", env.getProperty("db.driverClass.mysql"));
props.setProperty("hibernate.connection.url", env.getProperty("db.url"));
props.setProperty("hibernate.connection.username", env.getProperty("db.user"));
props.setProperty("hibernate.connection.password", env.getProperty("db.password"));
props.setProperty("hibernate.c3p0.min_size", "10");
props.setProperty("hibernate.c3p0.max_size", "50");
//props.setProperty("hibernate.c3p0.timeout", "1800");
props.setProperty("hibernate.c3p0.max_statements", "50");
props.setProperty("hibernate.c3p0.preferredTestQuery", "SELECT 1;");
props.setProperty("hibernate.c3p0.idle_test_period", "600");
props.setProperty("hibernate.c3p0.validate", "true");
props.setProperty("hibernate.c3p0.timeout", "300");
return new LocalSessionFactoryBuilder(shopDataSource)
.scanPackages("com.shop.domain")
.setProperties(props)
.buildSessionFactory();
}
//more datasources and sessionFactories - not needed for demonstration
}
Testing this with the following throws an error - everything works fine when not using @PropertySource for DataSource properties and env.getProperty():
Code:
@ContextConfiguration(classes= {PropertiesConfig.class, DevelopmentRepositoryConfig.class}, loader = AnnotationConfigContextLoader.class)
@ActiveProfiles("development")
public class HibernateConfigurationTest extends AbstractJUnit4SpringContextTests {
@Autowired
@Qualifier("shopSessionFactory")
private SessionFactory sessionFactory;
@Autowired
Environment env;
@Test
public void testEnvironment() {
assertTrue("environment is dev", "development".equals(env.getActiveProfiles()[0]));
assertTrue("shop user is root", "root".equals(env.getProperty("db.user")));
assertTrue("shop password is root", "root".equals(env.getProperty("db.password")));
assertTrue("shop url is", "jdbc:mysql://localhost/shop".equals(env.getProperty("db.url")));
assertTrue("shop driver is", "com.mysql.jdbc.Driver".equals(env.getProperty("db.driverClass.mysql")));
}
@Test
public void testHibernateConfiguration() {
// Spring IOC container instantiated and prepared sessionFactory
assertNotNull(sessionFactory);
}
}
I will end up with java.lang.IllegalStateException: Failed to load ApplicationContext and the following log:
Code:
14:09:10,119 DEBUG DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'developmentRepositoryConfig'
14:09:10,120 DEBUG DefaultListableBeanFactory:430 - Creating instance of bean 'developmentRepositoryConfig'
14:09:10,122 DEBUG InjectionMetadata:60 - Found injected element on class [com.wurthusa.intranet.config.DevelopmentRepositoryConfig$$EnhancerByCGLIB$$6a31034a]: AutowiredFieldElement for private javax.sql.DataSource com.shop.config.DevelopmentRepositoryConfig.shopDataSource
14:09:10,123 DEBUG InjectionMetadata:60 - Found injected element on class [com.shop.config.DevelopmentRepositoryConfig$$EnhancerByCGLIB$$6a31034a]: AutowiredFieldElement for private javax.sql.DataSource com.shop.config.DevelopmentRepositoryConfig.specialOrdersDataSource
14:09:10,123 DEBUG InjectionMetadata:60 - Found injected element on class [com.shop.config.DevelopmentRepositoryConfig$$EnhancerByCGLIB$$6a31034a]: AutowiredFieldElement for private javax.sql.DataSource com.shop.config.DevelopmentRepositoryConfig.vacationDataSource
14:09:10,123 DEBUG InjectionMetadata:60 - Found injected element on class [com.shop.config.DevelopmentRepositoryConfig$$EnhancerByCGLIB$$6a31034a]: AutowiredFieldElement for org.springframework.core.env.Environment com.shop.config.DevelopmentRepositoryConfig.env
14:09:10,123 DEBUG DefaultListableBeanFactory:504 - Eagerly caching bean 'developmentRepositoryConfig' to allow for resolving potential circular references
14:09:10,126 DEBUG InjectionMetadata:85 - Processing injected method of bean 'developmentRepositoryConfig': AutowiredFieldElement for private javax.sql.DataSource com.shop.config.DevelopmentRepositoryConfig.shopDataSource
14:09:10,127 DEBUG DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'shopDataSource'
14:09:10,127 DEBUG DefaultListableBeanFactory:430 - Creating instance of bean 'shopDataSource'
14:09:10,127 DEBUG DefaultListableBeanFactory:241 - Returning eagerly cached instance of singleton bean 'developmentRepositoryConfig' that is not fully initialized yet - a consequence of a circular reference
Could it be that @PropertySource is initialized too late to actually be used within the DevelopmentRepositoryConfig? Both tests will fail when using @PropertySource properties in DataSource/SessionFactory bean but pass when db.user etc. are set directly - meaning Environment itself seems to be fine.
Any input is appreciated,
Michael
dev.properties:
Code:
db.driverClass.mysql=com.mysql.jdbc.Driver
db.user.shop=root
db.password.shop=root
db.url.shop=jdbc\:mysql\://localhost/shop