Can't Autowire SessionFactory with Java Configuration - java

The configuration class name is marked in yellow color and it says Application context not configured for this file
My Config Class :
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("com.tornikeshelia.model");
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
private Properties getHibernateProperties(){
Properties prop = new Properties();
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL57InnoDBDialect");
return properties;
}
#Bean(name = "dataSource")
public BasicDataSource dataSource(){
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=utf-8");
ds.setUsername("username");
//ds.setPassword("");
return ds;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory){
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
I've commented out ds.setPassword because my test database doesn't have any password protection. Also the hibernate doesn't auto create tables from my Entity class , I think thats because of this configuration file not being read by Spring
When trying to autowire SessionFactor in my DaoImpl class via :
#Resource(name = "sessionFactory")
private SessionFactory session;
The error says Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personDaoImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.hibernate.SessionFactory com.tornikeshelia.dao.PersonDaoImpl.sessionFactory; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
SOLUTION :
The problem was 1)The location of config package and 2) in the warning message that was on the class name (yellowed out with message - Application context not configured for this file
So if anybody has same problem here's the solution -
1) move your config package inside the parent package where the model package is
2) Step on the class name (click anywhere on the class name) the yellow light bulb will appear, click on it and then click on configure application context, a new tab will appear where you should choose this class and press okay.

Try to edit your config class and update the transationManager() bean :
#Bean
public HibernateTransactionManager transactionManager(){
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory().getObject());
return txManager;
}
Your error may occur because you try to inject a bean that has not bean created yet.

Related

Unresolveable Circular reference error when configuring multiple datasources in a spring batch

I'm trying to configure two datasources in my spring batch application. One for batch metadata tables, and another for the business tables.
Snippet from my application.properties file:
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=
spring.batchdatasource.url=
spring.batchdatasource.username=
spring.batchdatasource.password=
spring.batchdatasource.driver-class-name=
My batch config file:
#Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{
#Autowired
private JobBuilderFactory jobs;
#Autowired
private StepBuilderFactory steps;
// #Autowired
// private DataSource dataSource;
#Autowired
private PlatformTransactionManager transactionManager;
#Bean(name = "batchDatasource")
#ConfigurationProperties(prefix="spring.batchdatasource")
public DataSource batchDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "primaryDatasource")
#ConfigurationProperties(prefix="spring.datasource")
#Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Override
public JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(batchDataSource());
// factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setTablePrefix("schema1"+ ".BATCH_");
factory.afterPropertiesSet();
return factory.getObject();
}
/* Job and step bean definitions here */
My main class is the one annotated with #EnableBatchProcessing
#SpringBootApplication
#EnableBatchProcessing
public class SpringBatchExample1Application {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
I'm getting this Requested bean is currently in creation: Is there an unresolvable circular reference? when trying to configure two datasources. It works fine when using a single datasource by autowiring(refer the commented out lines of code) instead of creating multiple beans.
Following is the exception snippet:
Error creating bean with name 'springBatchConfig': Unsatisfied dependency expressed through method 'setDataSource' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'batchDatasource': Requested bean is currently in creation: Is there an unresolvable circular reference?
I looked up and found out this occurs when there's a dependency on a bean which is still not created or is being created. I just see it in the createJobRepository method where datasource is being plugged. I still face the error even if I don't have the createJobRepository method.
It seems like the requirement is for the datasource beans to be created before others. I tried using the #Order annotation, but no luck.
EDIT:
I tried the solution from #Mykhailo Skliar's Accepted answer below, and serparated the Datasource beans into a new Configuration class. Though it resolved the initial Unresolveble circular reference issue anymore, it led me to the following error:
Error creating bean with name 'springBatchConfig': Invocation of init method failed; nested exception is org.springframework.batch.core.configuration.BatchConfigurationException: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
Based on this answer, I changed my url property names as follows:
spring.datasource.jdbc-url=
spring.datasource.jdbc-url=
Though it solved the jdbcUrl error, it posed another issue:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Reference to database and/or server name in 'sample-sql-server.schema1.MY_TABLE_NAME' is not supported in this version of SQL Server.
Both my data sources are Azure SQL server instances.
I looked up and found it was not possible to use multiple Azure SQL databases years ago, but based on this answer it should not be the case anymore.
The issue is most probably because of
factory.setDataSource(batchDataSource());
You should use autowired bean here, instead of calling batchDataSource()
I would split SpringBatchConfig in two beans:
#Configuration
public class DataSourceConfig {
#Bean(name = "batchDatasource")
#ConfigurationProperties(prefix="spring.batchdatasource")
public DataSource batchDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "primaryDatasource")
#ConfigurationProperties(prefix="spring.datasource")
#Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
}
#Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{
#Autowired
private JobBuilderFactory jobs;
#Autowired
private StepBuilderFactory steps;
#Qualifier("batchDataSource")
#Autowired
private DataSource batchDataSource;
#Autowired
private PlatformTransactionManager transactionManager;
#Override
public JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(batchDataSource);
factory.setTransactionManager(transactionManager);
factory.setTablePrefix("schema1"+ ".BATCH_");
factory.afterPropertiesSet();
return factory.getObject();
}
}

AutoConfigureTestDatabase with multiple DataSource beans

I have two DataSources in my application, which work as expected when connecting to the databases in a live environment. However, when writing unit tests for this application, I'm encountering problems with my bean definitions.
This is my primary DataSource configuration:
#Configuration
#EnableJpaRepositories(
basePackages = "foo.bar.repository.primary",
entityManagerFactoryRef = "primaryEntityManager",
transactionManagerRef = "primaryTransactionManager")
public class PrimaryDataSourceConfig {
#Bean
#Primary
#ConfigurationProperties("primary.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan("foo.bar.domain.entity");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
Map<String, String> properties = new HashMap<>();
properties.put("hibernate.implicit_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
properties.put("hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
em.setJpaPropertyMap(properties);
return em;
}
#Bean
#Primary
public PlatformTransactionManager primaryTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(primaryEntityManager().getObject());
return transactionManager;
}
}
I have a test where all I want to do is spin up the entire application context, looking like this.
#AutoConfigureTestDatabase
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ErpApplicationTest {
#Test
public void test() {
// Application started
}
}
However, when I run this test, I get the following error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primaryEntityManager' defined in class path resource [foo/bar/primaryDataSourceConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method 'primaryEntityManager' threw exception; nested exception is java.lang.IllegalArgumentException: No visible constructors in class org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceFactoryBean
What is causing this error, and what can I do to rectify it? Flyway is able to connect to the embedded H2 instance the annotation generates and run its migrations, but the primary DataSource, alongside its EntityManager fail at creation.
I resolved the issue by doing the following:
First I changed the AutoConfigureTestDatabase-annotation to not replace any DataSource:
#AutoConfigureTestDatabase(
replace = AutoConfigureTestDatabase.Replace.NONE)
I was now experiencing an error where I would timeout against the database. Since the AutoConfig defaults to an in-memory h2, I figured the previous database connection settings were incorrect. I changed my application.properties-file to contain the following:
primary.datasource.driver-class-name=org.h2.Driver
primary.datasource.jdbc-url=jdbc:h2:~;MODE=MYSQL
primary.datasource.username=
primary.datasource.password=
secondary.datasource.driver-class-name=org.h2.Driver
secondary.datasource.jdbc-url=jdbc:h2:~;MODE=MYSQL
secondary.datasource.username=
secondary.datasource.password=
Presumably this error occurred because the auto configuration couldn't properly replace the entityManager for my custom datasource. By ensuring the DataSource wasn't replaced, and ensuring the connection url was correct, the test went through as expected.

Hibernate SessionFactory annotation based configuration

My recent goal is to build a spring boot application, but without any XML config files (or as less as possible) so I would like to avoid using some XML files (i.e. web.xml) especially for some bean definition parts.
And here comes tougher part.
I want to inject using #Autowired annotation a SessionFactory bean into classes, but everytime I try to start application I get:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'temperatureController': Unsatisfied dependency expressed through field 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: EntityManagerFactory must not be null
Ok, I understand that Spring has no SessionFactory bean because it has no EntityManagerFactory.
So I would appreciate any suggestions how to solve this, but only with configuration by annotations.
So far I read similar post to mine about specifying in #Configuration class a bean this way:
#Bean
public HibernateJpaSessionFactoryBean sessionFactory() {
return new HibernateJpaSessionFactoryBean();
}
And then adding this line into properties file:
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
And finally #Autowired with SessionFactory should work good.
But, of course for me it's not working.
Any ideas what should I do different/better?
My properties file is very basic:
spring.jpa.show-sql = true
spring.datasource.password=mysql
spring.datasource.username=mysql
spring.datasource.testWhileIdle = true
spring.jpa.hibernate.ddl-auto = update
spring.datasource.validationQuery = SELECT 1
spring.datasource.url= jdbc:mysql://localhost:3306/sys
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
Usually when I want to define something simple I make a class that is similar to the following:
#Configuration
#EnableTransactionManagement
public class PersistanceJpaConfig {
#Bean
public LocalSessionFactoryBean hibernateSessionFactory(DataSource dataSource) {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setPackagesToScan(new String[] {
"my.entities.package"
});
sessionFactory.setHibernateProperties(additionalProperties());
return sessionFactory;
}
#Bean HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory);
return transactionManager;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306");
dataSource.setUsername("user");
dataSource.setPassword("password");
return dataSource;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL57InnoDBDialect");
return properties;
}
}
By using #EnableTransactionManagement and creating a bean of type LocalSessionFactoryBean, spring will automatically create a SessionFactory bean for you that you can inject/autowire anywhere.
Of course you can inject some of the configuration from properties files if needed.

NoSuchBeanDefinitionException: No qualifying bean of type JpaVendorAdapter found for dependency

I'm trying to setup Java-based hibernate in memory database and start using it from a test, but when Hibernate beans are loaded Application context fail with. The point if this exercise is to setup simple service with CRUD operations using CrudRepository for a few classes and WRITE
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.orm.jpa.JpaVendorAdapter] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 72 more
Related configuration and source code:
hibernate.properties
jdbc.driverClassName = org.hsqldb.jdbcDriver
jdbc.url = jdbc:hsqldb:mem:press
jdbc.username = user
jdbc.password =
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.show_sql = false
hibernate.format_sql = false
HibernateConfig.java - which fails to load
#Configuration
#EnableTransactionManagement
#PropertySource(value = { "classpath:hibernate.properties" })
public class HibernateConfig {
#Autowired
private Environment environment;
#Bean
public EntityManagerFactory entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("net.agilob.press.entity");
return lef.getNativeEntityManagerFactory();
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "net.agilob.press.entity" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("create-drop"));
return properties;
}
#Bean
#Autowired
public HibernateTemplate getHibernateTemplate(SessionFactory sessionFactory) {
HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
return hibernateTemplate;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
AppConfig.java - file loaded as configuration for test
#Configuration
#ComponentScan(basePackages = "net.agilob.press.entity")
#EnableJpaRepositories(basePackages = "net.agilob.press.entity.repository")
#Import(HibernateConfig.class)
public class AppConfig {
#Bean
public PostService getPostService() {
return new PostService();
}
}
PostServiceTest.java - this one should create instance(s) of Post, save it in memory database and extract later (just to see it works):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)
#Transactional
public class PostDAOTest {
#Autowired
private PostService postService;
#Before
public void setUp() {
Post post = new Post();
post.setContent("body");
post.setDescription("description");
post.setIntroduction("introduction");
post.setTitle("title");
post.setTitleBrowser("title browser");
postRepository.save(post);
}
#Test
public void testList() {
// checks if spring wiring was correct
assertNotNull("Problem with spring beans", postRepository);
assertFalse(postRepository.findTop10ByTitleOrderByIdAsc().isEmpty());
}
}
PostService:
#Service("postService")
#Transactional
public class PostService {
#Autowired
private PostRepository postRepository;
...
}
PostRepository:
public interface PostRepository extends BaseRepository<Post, Long> {
}
I tried to create one more #Beans annotated method in HibernateConfig that was bulding JpaVendorAdapter instance but when I run the test it was failing with:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManager]: Factory method 'createSharedEntityManager' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 59 more
Caused by: java.lang.NullPointerException
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.initProxyClassLoader(SharedEntityManagerCreator.java:199)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.<init>(SharedEntityManagerCreator.java:191)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:163)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:120)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 60 more
my pom.xml
so I think something else is wrong in the setup.
Any help how to design and setup it in a better way very appreciated.
In order for your entityManagerFactory to know the provider class as well as jpa dialect, you need to set jpaVendorAdaptor on your entityManagerFactory bean. This can be done as
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setDatabase(Database.HSQL);
jpaVendorAdapter.setDatabasePlatform(MySQL5Dialect.class.getName());
jpaVendorAdapter.setGenerateDdl(false);
return jpaVendorAdapter;
}
and calling this method inside your entityManagerFactory as follows :
lef.setJpaVendorAdapter(jpaVendorAdapter());
Are you sure that you have all required dependencies?
Is HibernateJpaVendorAdapter available on your classpath?
Try to add dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

How do I ensure dependent configurations are initialized with Spring #Configuration annotation?

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)):
208 [Thread-0] INFO org.springframework.context.annotation.ConfigurationClassEnhancer
Successfully enhanced com.bjk.observation.server.config.DaoConfig; enhanced class name is: com.bjk.observation.server.config.DaoConfig$$EnhancerByCGLIB$$96e1956
229 [Thread-0] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#185572a: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.annotation.internalPersistenceAnnotationProcessor, daoConfig,com.bjk.observation.server.config.DataSourceConfig#0, dataSource, com.bjk.observation.server.config.HibernateConfig#0, namingStrategy, sessionFactory, jdbcTemplate, txManager, hibernateTemplate, phenomenonGroupDao, phenomenonDao, discretePhenomenonDao]; root of factory hierarchy DaoConfig constructing...
252 [Thread-0] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory
Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#185572a: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.annotation.internalPersistenceAnnotationProcessor, daoConfig, com.bjk.observation.server.config.DataSourceConfig#0, dataSource, com.bjk.observation.server.config.HibernateConfig#0, namingStrategy, sessionFactory, jdbcTemplate, txManager, hibernateTemplate, phenomenonGroupDao, phenomenonDao, discretePhenomenonDao]; root of factory hierarchy
253 [Thread-0] ERROR org.springframework.web.context.ContextLoader
Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'daoConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bjk.observation.server.config.HibernateConfig com.bjk.observation.server.config.DaoConfig.hibernateConfig; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.bjk.observation.server.config.HibernateConfig#0': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.bjk.observation.server.config.HibernateConfig]: Constructor threw exception; nested exception is java.lang.NullPointerException
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.

Categories

Resources