I am trying to use @Configuration annotations to wire up my application but I keep getting a NullPointerException in one of the initializers because the bean it refers to is not yet initialized (I think). I have tried specifying in the web.xml just the 'root' config class and also tried doing a package scan and neither seem to work.
Sorry about the big code dump. I tried to produce a much simpler set of classes to reproduce the issue, but of course, when I did that, everything worked fine. Here are my classes (imports elided):
DataSourceConfig.java:
@Configuration
public class DataSourceConfig {
public DataSourceConfig() {
System.err.println("DataSourceConfig constructed...");
}
@Bean
public DataSource dataSource() {
BasicDataSource bean = new BasicDataSource();
bean.setDriverClassName("com.mysql.jdbc.Driver");
bean.setUrl("jdbc:mysql://localhost:3306/observation");
bean.setUsername("observation");
bean.setPassword("*******");
bean.setInitialSize(1);
bean.setMaxActive(5);
bean.setTestOnBorrow(true);
System.err.println("dataSource bean initialized: " + bean.toString());
return bean;
}
}
HibernateConfig.java
@Configuration
@Import(DataSourceConfig.class)
public class HibernateConfig {
public HibernateConfig() {
System.err.println("HibernateConfig constructing...");
}
@Autowired
private DataSourceConfig dataSourceConfig;
@Bean
protected NamingStrategy namingStrategy() {
return new ImprovedNamingStrategy();
}
private AnnotationSessionFactoryBean sessionFactoryBean = null;
@Bean
@DependsOn("dataSourceConfig")
public AnnotationSessionFactoryBean sessionFactory() {
if (sessionFactoryBean == null) {
sessionFactoryBean = new AnnotationSessionFactoryBean();
NPE Here--> sessionFactoryBean.setDataSource(dataSourceConfig.dataSource());
sessionFactoryBean.setSchemaUpdate(true);
sessionFactoryBean.setNamingStrategy(namingStrategy());
sessionFactoryBean.setPackagesToScan(new String[] {
"com.newco.observations.domain",
"com.newco.observations.domain.*" });
Properties props = new Properties();
props.setProperty("hibernate.default_schema", "observation");
props.setProperty("hibernate.dialect",
"org.hibernate.dialect.MySQLDialect");
props.setProperty("hibernate.show_sql", "true");
sessionFactoryBean.setHibernateProperties(props);
System.err.println("sessionFactory initialized");
}
return sessionFactoryBean;
}
@Bean
@DependsOn("dataSourceConfig")
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSourceConfig.dataSource());
}
@Bean
@DependsOn("sessionFactory")
public ResourceTransactionManager txManager() {
HibernateTransactionManager bean = new HibernateTransactionManager();
bean.setSessionFactory((SessionFactory) sessionFactory().getObject());
return bean;
}
@Bean
@DependsOn("sessionFactory")
public HibernateTemplate hibernateTemplate() {
return new HibernateTemplate((SessionFactory) sessionFactory()
.getObject());
}
}
DaoConfig.java:
@Configuration
@Import(HibernateConfig.class)
public class DaoConfig {
public DaoConfig()
{
System.err.println("DaoConfig constructing...");
}
private @Autowired HibernateConfig hibernateConfig;
@Bean
@DependsOn("hibernateTemplate")
public PhenomenonGroupDao phenomenonGroupDao()
{
PhenomenonGroupDaoImpl bean = new PhenomenonGroupDaoImpl();
bean.setHibernateTemplate(hibernateConfig.hibernateTemplate());
return bean;
}
@Bean
@DependsOn("hibernateTemplate")
public PhenomenonDao phenomenonDao()
{
PhenomenonDaoImpl bean = new PhenomenonDaoImpl();
bean.setHibernateTemplate(hibernateConfig.hibernateTemplate());
return bean;
}
@Bean
@DependsOn("hibernateTemplate")
public DiscretePhenomenonDao discretePhenomenonDao()
{
DiscretePhenomenonDaoImpl bean = new DiscretePhenomenonDaoImpl();
bean.setHibernateTemplate(hibernateConfig.hibernateTemplate());
return bean;
}
}
You can see from the System.err.println's and the @DependsOn annotations a kind of flailing about that I'm doing.
I can provide the full log if it's useful, but here is what I think are the relevant lines (with a little formatting to make it more readable (maybe)):
The problem, I believe is here:
@Autowired
private DataSourceConfig dataSourceConfig;
You're not supposed to explicitly wire yourself with other @Configuration
-annotated classes, but rather the beans that they produce. Spring will sort out the plumbing for you.
So replace the above field with the simpler:
@Autowired
private DataSource dataSource;
Spring will fetch the DataSource
from DataSourceConfig
and transparently inject it into the field.
Similarly, replace
@Autowired
private HibernateConfig hibernateConfig;
with
@Autowired
private HibernateTemplate hibernateTemplate;
You'll notice that the @Configuration
style doesn't feel as nice when working with factory beans like AnnotationSessionFactoryBean
, since you often have to call getObject()
on it yourself. Sometimes, it's more natural to use XML config, and mix it with the java config style.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With