This question already has answers here:
What exactly is Field Injection and how to avoid it?
(4 answers)
Spring setter injection and constructor injection
(2 answers)
Spring Auto Components Scanning with Constructor injection
(3 answers)
Closed 4 years ago.
I have library module which I want to use to store Hibernate models. I ask have Spring WAR package which I want to use.
Main Spring WAR:
#Configuration
#EnableTransactionManagement
public class ContextDatasource {
#Bean
public LocalSessionFactoryBean sessionFactory() throws NamingException {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "org.plugin.database.models" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() throws NamingException {
return (DataSource) new JndiTemplate().lookup("java:/global/production_gateway");
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() throws NamingException {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
return hibernateProperties;
}
}
Library DAO:
public class BlacklistsDaoHibernate implements BlacklistsDao {
Session session;
#Autowired
SessionFactory sessionFactory;
public BlacklistsDaoHibernate() {
session = sessionFactory.getCurrentSession();
}
#Override
public void saveOrUpdate(BlacklistsModel blacklistsModel) throws Exception {
try {
session.getTransaction().begin();
session.saveOrUpdate(blacklistsModel);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
throw new Exception("Error");
}
}
But I get NPE at this line session = sessionFactory.getCurrentSession();
What is the proper way to use sessionFactory into the Library Jar module?
You can use #PostConstruct or constructor injection. Spring instantiates your object, then resolves its #Autowired fields. You can ask that it resolve your object's dependencies prior to instantiating the object via constructor injection.
With constructor injection:
SessionFactory sessionFactory;
Session session;
public BlacklistsDaoHibernate(#Autowired SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
this.session = sessionFactory.getCurrentSession();
}
With #PostConstruct:
#Autowired
SessionFactory sessionFactory;
Session session;
#PostConstruct
void init() {
this.session = sessionFactory.getCurrentSession();
}
Edit: If your goal is just to resolve the NullPointerException as mentioned in the comments, use this instead:
#PostConstruct
void init() {
this.session = sessionFactory.openSession();
}
There's an example of the typical usage of SessionFactory at https://www.java2novice.com/hibernate/session-factory.
Related
I try to implement a RESTful WebService that is able to stream millions of records directly from database.
I'm using SpringBoot 2.2.5, Hibernate 5 and PostgreSQL 11
According to this post:
https://www.airpair.com/java/posts/spring-streams-memory-efficiency
one step is needed to set the flag "allowResultAccessAfterCompletion" to true.
But how can I do this in Spring Boot?
So far I do not have any SessionFactory, EntityManagerFactory, Datasource, ... configuration in my application. Everything is autoconfigured by SpringBoot.
If I add the proposed configuration below, the application won't start because of missing SessionFactory.
#Configuration
#EnableTransactionManagement
public class DataConfig {
#Autowired #Bean
public PlatformTransactionManager txManager(SessionFactory sf) {
HibernateTransactionManager mgr = new HibernateTransactionManager(sf);
mgr.setAllowResultAccessAfterCompletion(true);
return mgr;
}
... (the rest of your data config, including the LocalSessionFactoryBean) ...
}
If I provide a SessionFactory bean by unwrapping it from EntityManagerFactory, I get another exception:
Unsatisfied dependency expressed through field 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'getSessionFactory': Requested bean is currently in creation: Is there an unresolvable circular reference?
Does anyone have a working configuration for my setup?
Can't this flag simply be set by some configuration value in application.properties?
Thank you!
First of all you need to decide whether you need to use Hibernate or Spring JPA for your project. Work with the framework and not against it. Using jpa classes are preferred over hibernate classes by most people today.
Since you are using springboot , the best approach is to work with the framework and use spring-boot-starter-data-jpa which will automatically configure all your necessary beans at startup. In that case, you could provide your own custom beans to override parameters as you want.
In the sample code that you provided in the question, you are using Hibernate classes directly , so you will have to manually create all the necessary beans as spring won't work with you for that unless you disable the auto-configurations which might be causing the circular dependency issue for you.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories("com.sample.spring.repository")
#PropertySource("classpath:database.properties")
public class DataConfig {
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
#Autowired
Environment environment;
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.sample.spring");
lfb.setJpaProperties(hibernateProps());
return lfb;
}
#Bean
DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(environment.getProperty(PROPERTY_URL));
ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
return ds;
}
Properties hibernateProps() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
}
#Bean
JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
You can very well provide your own the SessionFactory as well in which case spring boot will not create another one for you. Following is excerpt from Bootstrapping Hibernate 5 with Spring article, feel free to tweak it as per your needs
#Configuration
#EnableTransactionManagement
public class HibernateConf {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(
{"com.baeldung.hibernate.bootstrap.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("sa");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setAllowResultAccessAfterCompletion(true);
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty(
"hibernate.hbm2ddl.auto", "create-drop");
hibernateProperties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.H2Dialect");
return hibernateProperties;
}
}
Another approach is to use BeanPostProcessor if you know that spring boot is already creating a HibernateTransactionManager in it's own lifecycle. Following is what the outline of the this BeanPostProcessor would look like
public class HTMPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof HibernateTransactionManager) {
((HibernateTransactionManager)bean).setAllowResultAccessAfterCompletion(true);
}
return bean; // you can return any other object as well
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean; // you can return any other object as well
}
}
Hope this helps!!
I don’t quite understand how this can be, but methods marked as #Bean are not initialized when I run them through the WebApplicationInitializer. In the debugger, you can only get to the #Autowired setters inside the #Configuration classes, but I don't see the initialization of the beans. When I start Spring context with Junit, it works fine.
Exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.hibernate.SessionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
WebServiceDispatcherServletInitializer
public class WebServiceDispatcherServletInitializer implements WebApplicationInitializer {
private static final String SERVICE_DISPATCHER_SERVLET = "service_dispatcher_servlet";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebServiceConfig.class, RootConfig.class, PersistenceConfig.class);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new CXFServlet());
dispatcher.addMapping("/services/*");
}
}
UPD: PersistenceConfig
#Configuration
#ComponentScan("com.softcomputer")
#PropertySource({"classpath:persistence-postgres.properties"})
#EnableTransactionManagement
public class PersistenceConfig {
private Environment environment;
#Autowired
public void setEnvironment(Environment environment) {
this.environment = environment;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory);
return transactionManager;
}
#Bean
#Profile("postgres")
public DataSource postgresDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(requireNonNull(environment.getProperty("jdbc.postgres.driverClassName")));
dataSource.setUrl(requireNonNull(environment.getProperty("jdbc.postgres.connection_url")));
dataSource.setUsername(requireNonNull(environment.getProperty("jdbc.postgres.username")));
dataSource.setPassword(requireNonNull(environment.getProperty("jdbc.postgres.password")));
return dataSource;
}
#Bean
#Profile("postgres")
public LocalSessionFactoryBean postgresSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(postgresDataSource());
sessionFactory.setPackagesToScan(
new String[]{"com.softcomputer", "com.softcomputer.testdomain"});
sessionFactory.setHibernateProperties(postgresAdditionalProperties());
return sessionFactory;
}
private Properties postgresAdditionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", requireNonNull(environment.getProperty("hibernate.postgres.hbm2ddl.auto")));
hibernateProperties.setProperty("hibernate.dialect", requireNonNull(environment.getProperty("hibernate.postgres.dialect")));
hibernateProperties.setProperty("hibernate.show_sql", requireNonNull(environment.getProperty("hibernate.postgres.show_sql")));
hibernateProperties.setProperty("hibernate.default_schema", requireNonNull(environment.getProperty("hibernate.postgres.default_schema")));
hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", requireNonNull(environment.getProperty("hibernate.postgres.globally_quoted_identifiers")));
return hibernateProperties;
}
}
UPD1: Beans in WebServiceConfig.class are not initialized either. But RootConfig.class is initialized fine (all config classes has #Configuration annotation)
UPD2: Maybes WebApplicationInitializer.onStartup expect another configuration, as szatkus said. Then what kind of startup should be used to run new CXFServlet() with such Configuration classes?
LocalSessionFactoryBean doesn't implement SessionFactory interface. Maybe try:
#Bean
#Autowired
public SessionFactory sessionFactory(LocalSessionFactoryBean sessionFactoryBean) {
return bean.getObject();
}
I have the test class which testing my DAO class. In theory, it should run a chain of each before → test → after in one transaction and make rollback after that, but seemingly it is not. Every time creates a new id (123->456 instead of 123->123). I guess that in-memory DBs (I use H2) works this way, and I was not mistaken. With Postgres setup, it works good enough.
I've checked:
configurations, annotations, and propagation levels
I tried to use hibernate.connection.autocommit = false
HSQLDB
But I didn't find a mistake there.
TransactionSynchronizationManager.isActualTransactionActive() returns true.
PersistenceConfig:
#Configuration
#ComponentScan("com.beginnercourse.softcomputer")
#PropertySource({"classpath:persistence-postgres.properties"})
#PropertySource({"classpath:persistence-h2.properties"})
#EnableTransactionManagement
public class PersistenceConfig {
#Autowired
private Environment environment;
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory);
return transactionManager;
}
#Bean
#Profile("postgres")
public DataSource postgresDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(requireNonNull(environment.getProperty("jdbc.postgres.driverClassName")));
dataSource.setUrl(requireNonNull(environment.getProperty("jdbc.postgres.connection_url")));
dataSource.setUsername(requireNonNull(environment.getProperty("jdbc.postgres.username")));
dataSource.setPassword(requireNonNull(environment.getProperty("jdbc.postgres.password")));
return dataSource;
}
#Bean
#Profile("postgres")
public LocalSessionFactoryBean postgresSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(postgresDataSource());
sessionFactory.setPackagesToScan(
new String[]{"com.beginnercourse.softcomputer"});
sessionFactory.setHibernateProperties(postgresAdditionalProperties());
return sessionFactory;
}
private Properties postgresAdditionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", requireNonNull(environment.getProperty("hibernate.postgres.hbm2ddl.auto")));
hibernateProperties.setProperty("hibernate.dialect", requireNonNull(environment.getProperty("hibernate.postgres.dialect")));
hibernateProperties.setProperty("hibernate.show_sql", requireNonNull(environment.getProperty("hibernate.postgres.show_sql")));
hibernateProperties.setProperty("hibernate.default_schema", requireNonNull(environment.getProperty("hibernate.postgres.default_schema")));
// hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", requireNonNull(environment.getProperty("hibernate.cache.use_second_level_cache")));
// hibernateProperties.setProperty("hibernate.cache.use_query_cache", requireNonNull(environment.getProperty("hibernate.cache.use_query_cache")));
return hibernateProperties;
}
#Bean
#Profile("oracle")
public DataSource oracleDataSource() throws NamingException {
return (DataSource) new JndiTemplate().lookup(requireNonNull(environment.getProperty("jdbc.url")));
}
#Bean
#Profile("test")
public LocalSessionFactoryBean testSessionFactory(DataSource dataSource ) {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
// postgresSessionFactory.setDataSource(postgresDataSource());
sessionFactory.setDataSource(dataSource);
sessionFactory.setPackagesToScan(
new String[]{"com.beginnercourse.softcomputer"});
sessionFactory.setHibernateProperties(testAdditionalProperties());
return sessionFactory;
}
#Bean
#Profile("test")
public DataSource h2DataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(requireNonNull(environment.getProperty("jdbc.h2.driverClassName")));
dataSource.setUrl(requireNonNull(environment.getProperty("jdbc.h2.connection_url")));
dataSource.setUsername(requireNonNull(environment.getProperty("jdbc.h2.username")));
dataSource.setPassword(requireNonNull(environment.getProperty("jdbc.h2.password")));
return dataSource;
}
private Properties testAdditionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", requireNonNull(environment.getProperty("hibernate.h2.hbm2ddl.auto")));
hibernateProperties.setProperty("hibernate.dialect", requireNonNull(environment.getProperty("hibernate.h2.dialect")));
hibernateProperties.setProperty("hibernate.show_sql", requireNonNull(environment.getProperty("hibernate.h2.show_sql")));
hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", requireNonNull(environment.getProperty("hibernate.h2.globally_quoted_identifiers")));
hibernateProperties.setProperty("hibernate.connection.autocommit", requireNonNull(environment.getProperty("hibernate.h2.connection.autocommit")));
return hibernateProperties;
}
}
H2 Properties
jdbc.h2.driverClassName=org.h2.Driver
jdbc.h2.connection_url=jdbc:h2:mem:e-commerce
jdbc.h2.username=sa
jdbc.h2.password=sa
hibernate.h2.dialect=org.hibernate.dialect.H2Dialect
hibernate.h2.show_sql=false
hibernate.h2.hbm2ddl.auto=update
hibernate.h2.globally_quoted_identifiers=true
hibernate.h2.connection.autocommit = false
TestDaoImpl
#ActiveProfiles(profiles = "test")
//#ActiveProfiles(profiles = "postgres")
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {
WebConfig.class,
PersistenceConfig.class,
})
#WebAppConfiguration
#Transactional
#Rollback
public class CustomerDaoImplTest {
#Autowired
private CustomerDao customerDao;
#Before
public void setUp() throws Exception {
CustomerEntity veronicaCustomer = new CustomerEntity();
veronicaCustomer.setName("Veronica");
customerDao.create(veronicaCustomer);
CustomerEntity hannaCustomer = new CustomerEntity();
hannaCustomer.setName("Hanna");
customerDao.create(hannaCustomer);
CustomerEntity ericCustomer = new CustomerEntity();
ericCustomer.setName("Eric");
customerDao.create(ericCustomer);
}
#After
public void tearDown() throws Exception {
customerDao.remove((long) 1);
customerDao.remove((long) 2);
customerDao.remove((long) 3);
}
#Test
public void find_must_return_an_object_by_id() throws NoCustomerWithSuchParametersException {
CustomerEntity customer = new CustomerEntity();
customer.setName("Veronica");
assertEquals(customerDao.find((long) 1).get().getName(), customer.getName());
}
#Test(expected = EntityNotFoundException.class)
public void should_optional_empty() {
assertEquals(customerDao.find((long) 55), Optional.empty());
}
}
Has anyone else come across something similar?
What makes you think the transaction is not being rolled back?
Ids with values 1,2,3 were allocated and, despite the rollback, the H2 database has simply declined to reuse them.
There's a discussion on that here (in terms of MySQL but similar behaviour) MySQL AUTO_INCREMENT does not ROLLBACK.
You could reset the auto-increment value between tests:
Resetting autoincrement in h2
or you could simply update your code to manually set the identifiers:
CustomerEntity veronicaCustomer = new CustomerEntity();
veronicaCustomer.setid(1L);
veronicaCustomer.setName("Veronica");
According to this question (H2 equivalent to SET IDENTITY_INSERT ) that should work in H2 without any issues. With other databases (SQLServer for example ) you may need to explicitly enable identity inserts to manually set a value on an identity column.
I'm migrating legacy app to Spring-boot and have to integrate an hibernate named query mapping file (previously configured in persitence.xml file).
I've come out with a solution with an
...
#Autowired
private DataSource dataSource;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
//...
sessionFactoryBean.setMappingResources("META-INF/named-queries.hbm.xml");
return sessionFactoryBean;
}
But i'm ending having an entityManager bean and a sessionFactory bean in my application!
is it a good solution according to you?
Is there a way to add somehow the hibernate mapping file (named-query.hbm.xml) to the entityManager without using the sessionFactory bean?
Thanks in advance for you suggestions
** EDIT **
fro JB Nizet's suggestion, also come up with another solution
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource);
// ...
entityManagerFactory.setMappingResources("META-INF/named-queries.hbm.xml");
return entityManagerFactory;
}
and in my DAO/Service, i can still get hibernate session with:
private Session getSession() {
//return this.sessionFactory.getCurrentSession();
return this.entityManager.unwrap(Session.class);
}
But if someone nows if we can do the same thing with spring-boot auto-config with properties, it's welcomed!
Put the *.hbm.xml files under the src/main/resources folder and Spring Boot can automatically scan for them.
If you want to specify the location in the application.properties file, define them to the spring.jpa.mapping-resources attribute.
spring.jpa.mapping-resources=hibernate/MyMapping.hbm.xml,hibernate/MyMapping2.hbm.xml
Tested in SpringBoot 2.1.3, following is the folder structure
src/main/resources/hibernate : Store all the *.hbm.xml files
src/main/resources/application.properties : define the spring boot properties
And if you want to get the hibernate session in your Dao classes, define them as follows:
#Repository
#Transactional
public class XxxDao {
#Autowired
private EntityManager entityManager;
private Session getSession() {
return entityManager.unwrap(Session.class);
}
...
}
#Autowired
private ResourceLoader rl;
#Bean
public LocalSessionFactoryBean sessionFactory() throws IOException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setMappingLocations(loadResources());
}
public Resource[] loadResources() {
Resource[] resources = null;
try {
resources = ResourcePatternUtils.getResourcePatternResolver(rl)
.getResources("classpath:/hibernate/*.hbm.xml");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resources;
}
I am getting the error as in the question. My Dao Implement Class is as follows :
package com.argus.intenew;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
#Autowired
AnnotationSessionFactoryBean sessionFactory;
public UserDaoImpl() {
}
public AnnotationSessionFactoryBean getCurrentSessionFactory() {
return sessionFactory;
}
public void setCurrentSessionFactory(AnnotationSessionFactoryBean sessionfactory) {
this.sessionFactory = sessionfactory;
}
#Override
public void addUser(UserMap userMap) {
System.out.println("33333333333333333333");
getHibernateTemplate().save(userMap);
}
#Override
public List<User> findAllUser() {
return getHibernateTemplate().find("from User");
}
#Override
public void deleteUser(UserMap user) {
getHibernateTemplate().delete(user);
}
#Override
public void updateUser(UserMap user) {
getHibernateTemplate().update(user);
}
}
And my configuration class is as follows:
package com.argus.intenew;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
#Configuration
#ComponentScan(basePackages = {"com.argus.intenew"})
public class Webconfig {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "org.hibernate.dialect.MySQLDialect ";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "true";
#Bean
public DataSource dataSource() {
System.out.println("----------InDATAsource------------");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/MyUser");
dataSource.setUsername("root");
dataSource.setPassword("XXX");
System.out.println("----------OutofDATAsource------------");
return dataSource;
}
#Bean
public AnnotationSessionFactoryBean sessionFactory() {
System.out.println("----------InsessionFactory------------");
AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
String[] pckage={"com.argus.intenew"};
sessionFactory.setPackagesToScan(pckage);
sessionFactory.setHibernateProperties(hibProperties());
System.out.println("----------Outof session------------");
return sessionFactory;
}
private Properties hibProperties() {
System.out.println("----------InhipProp------------");
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.MySQLDialect ");
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, "true");
System.out.println("----------outofhip------------");
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory().getObject());
return transactionManager;
}
#Bean
public UserBoImpl userBo() {
System.out.println("----------InUserBo------------");
UserBoImpl userBo= new UserBoImpl();
userBo.setUserDao(userDao());
System.out.println("----------OutofUserbo------------");
return userBo;
}
#Bean
public UserDaoImpl userDao() {
System.out.println("----------InUserDao------------");
UserDaoImpl userDao=new UserDaoImpl();
userDao.setCurrentSessionFactory(sessionFactory());
System.out.println("----------OutofUserDao------------");
return userDao;
}
}
Anyone please help and tell me what is the correct way to do this with annotations.
Here I am not using any xml file.
Your DAO implementation is not leveraging its superclass correctly.
You're injecting a Spring FactoryBean<SessionFactory> when it really needs a Hibernate SessionFactory.
It's not actually using the injected dependency.
You're attempting to use HibernateDaoSupport#getHibernateTemplate() without giving it a reference to a SessionFactory or a HibernateTemplate.
Note that HibernateDaoSupport will create its own HibernateTemplate as long as you give it a SessionFactory.
I suggest you make the following changes:
Remove AnnotationSessionFactoryBean sessionFactory from UserDaoImpl
Fix configuration of UserDaoImpl by leveraging its inherited setSessionFactory(SessionFactory) method
So you actually end up with this DAO code:
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
#Override
public void addUser(UserMap userMap) {
getHibernateTemplate().save(userMap);
}
#Override
public List<User> findAllUser() {
return getHibernateTemplate().find("from User");
}
#Override
public void deleteUser(UserMap user) {
getHibernateTemplate().delete(user);
}
#Override
public void updateUser(UserMap user) {
getHibernateTemplate().update(user);
}
}
And this configuration code:
#Configuration
#ComponentScan(basePackages = {"com.argus.intenew"})
public class Webconfig {
//snip...
#Bean
public UserDaoImpl userDao() {
UserDaoImpl userDao=new UserDaoImpl();
userDao.setSessionFactory(sessionFactory().getObject());
return userDao;
}
}
Note that it's ok to return the FactoryBean from the sessionFactory() configuration method since Spring will detect and utilize its lifecycle methods (via InitializingBean and DisposableBean), but you need to accommodate by calling the FactoryBean method getObject() yourself.
Don't user HibernateDaoSupport and/or HibernateTemplate. With the release of Hibernate 3.0.1 that support should be regarded deprecated. As mentioned in the reference guide implement the dao/repository based on plain hibernate.
Your dao will look like
#Repository
public class UserDaoImpl implements UserDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public void addUser(UserMap userMap) {
System.out.println("33333333333333333333");
sessionFactory.getCurrentSession().save(userMap);
}
#Override
public List<User> findAllUser() {
return sessionFactory.getCurrentSession().createQuery("from User").list();
}
#Override
public void deleteUser(UserMap user) {
sessionFactory.getCurrentSession().delete(user);
}
#Override
public void updateUser(UserMap user) {
sessionFactory.getCurrentSession().update(user);
}
}
As you are already using the #ComponentScan annotation (and I assume yo have your BO annotated with #Service and properly annotated with #Autowired there is no need to explictly configure you dao and service in the configuration.
#Configuration
#ComponentScan(basePackages = {"com.argus.intenew"})
public class Webconfig {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "org.hibernate.dialect.MySQLDialect ";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "true";
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/MyUser");
dataSource.setUsername("root");
dataSource.setPassword("XXX");
return dataSource;
}
#Bean
public AnnotationSessionFactoryBean sessionFactory() {
AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
String[] pckage={"com.argus.intenew"};
sessionFactory.setPackagesToScan(pckage);
sessionFactory.setHibernateProperties(hibProperties());
return sessionFactory;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.MySQLDialect ");
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, "true");
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
}
A note regarding DriverManagerDataSource this is nice for testing but please don't use this in production (unless you want an application that doesn't perform). Use a proper JDBC Connection Pool instead.
A final note, if you really want productivity drop hibernate, switch to JPA and use Spring Data JPA for your repositories. Saves you writing a lot of implementation code. (And the best maintainable and testable code is code not written :) ).