Hibernate SessionFactory vs Spring LocalSessionFactoryBean - spring

I am trying to move a spring3.2.x + hibernate4.x setup from a xml to java configuration.
Heres a snippet of the existing code:
import org.hibernate.SessionFactory;
import org.hibernate.Query;
import org.hibernate.Session;
public class StockDaoImpl implements StockDao{
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(Stock stock){
Session session = getSessionFactory().openSession();
try{
session.save(stock);
}
finally{
session.close();
}
}
The spring config file
<!-- Stock Data Access Object -->
<bean id="stockDao" class="com.data.dao.StockDaoImpl" >
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="dataSource">
.....
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
......
</property>
<property name="mappingResources">
.......
</property>
</bean>
This works fine - but how do i re-define this config in java?
Heres an attempt -
#Bean
public StockDao stockDao() {
StockDaoImpl dao=new StockDaoImpl();
dao.setSessionFactory(sessionFactory());
return dao;
}
......
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { .....});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
But this wont compile as the sessionFactory being referred to is not Spring's LocalSessionFactoryBean?
How do I reconcile this?

LocalSessionFactoryBean is a FactoryBean<SessionFactory>. It means that it allows creating instances of SessionFactory.
So you just need
public StockDao stockDao() {
StockDaoImpl dao=new StockDaoImpl();
dao.setSessionFactory(sessionFactory().getObject());
return dao;
}
But I wouldn't create DAOs explicitel like that. Simply annotate your DAO with #Repository, and autowire the session factory using #Autowired. Make sure the Java config class is annotated with #ComponentScan("the.base.package.of.daos")

Missing getObject() call in return.
Substituite with return sessionFactory.getObject() (and change return type,too!)

JB Nizet's answer helped me, but I needed to declare the beans separately for it to work:
#Bean
public LocalSessionFactoryBean sessionFactoryBean(final DataSource dataSource,
final Properties hibernateProperties,
final List<String> hibernateMappings) {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
sessionFactoryBean.setMappingResources(hibernateMappings.toArray(new String[hibernateMappings.size()]));
return sessionFactoryBean;
}
#Bean
public SessionFactory sessionFactory(LocalSessionFactoryBean sessionFactoryBean) {
return sessionFactoryBean.getObject();
}

Related

Spring #Autowire retuning null while creating an object

I am new to this Spring and trying to learn it.
I am using basic auth jersey and using spring to inject my db props and instantiate the class. However I am getting null pointer exception when I try this with a REST call using postman.
Below is code snippet
AppContx.xml
<context:annotation-config />
<context:component-scan base-package="com.rest" />
<bean id="userDao" class="com.rest.dao.UserDao">
<property name="dataSource" ref="ds" />
</bean>
<bean id="ds" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/Weber" />
<property name="resourceRef" value="true" />
</bean>
Filter
#Provider
public class AuthenticationFilter implements ContainerRequestFilter {
/*ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
IuserDao userDao = (IuserDao) ctx.getBean("userDao");*/
#Autowired
UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
if (userDao.getUSerForAuthentication(password, username) == 1) {
String userRole = "ADMIN";
if (rolesSet.contains(userRole)) {
isAllowed = true;
}
DAO
#Autowired
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
I am successfully able to inject DB properties to my data source using #Autowired but I am unable to instantiate the UserDao in my Filter class.
Thank You
Mark

#Transactional on service layer not rolling back Spring MVC+Hibernate

I have 3 classes (UserSrvImpl in service layer, MailDaoImpl and UserDaoImpl in dao (repository) layer). In my service layer (UserSrvImpl), i have a method that calls a method from MailDaoImpl and a method from UserDaoImpl. These 2 dao methods have to save objects in 2 different tables. These 2 tables have a OneToOne relasionship. My problem is when the first insertion succeeds and the second fails, there is no roll back. I'm struggling with this problem since a week. I applied all the solutions that i found in google, but still no success. Can you please give me a help.
Here is my service layer:
#Service
public class UserSrvImpl implements IUserSrv {
#Autowired
private IUserDao userDao;
#Autowired
private IMailDao mailDao;
#Override
#Transactional
public boolean create(UserDto userDto) {
boolean result = false;
try {
User userToSave = transformDtoToEntity(userDto);
MailToken mailToken = createMailTokenForNewUser(userToSave);
userToSave.setMailToken(mailToken);
if (mailDao.createMailToken(mailToken)) {
result = userDao.create(userToSave);
}
} catch (Exception ex) {
}
return result;
}
The service is calling the dao's method mailDao.createMailToken and userDao.create. If the first succeeds and the second fails, there is no roll back on the first table in the database.
Below is the code in MailDao:
#Repository
public class MailDao implements IMailDao {
#Autowired
private SessionFactory sessionFactory;
public Session getSession() {
Session sess = this.sessionFactory.getCurrentSession();
if (sess == null) {
sess = this.sessionFactory.openSession();
}
return sess;
}
#Override
public boolean createMailToken(MailToken mailToken) {
try {
getSession().save(mailToken);
return true;
} catch (HibernateException ex) {
} catch (Exception ex) {
// TODO: handle exception
}
return false;
}
Below is the code in UserDaoImpl:
#Repository
public class UserDaoImpl implements IUserDao {
#Autowired
private SessionFactory sessionFactory;
public Session getSession() {
Session sess = this.sessionFactory.getCurrentSession();
if (sess == null) {
sess = this.sessionFactory.openSession();
}
return sess;
}
#Override
public boolean create(User userToSave) {
try {
getSession().save(userToSave);
return true;
} catch (HibernateException ex) {
ex.printStackTrace();
} catch (Exception ex) {
// TODO: handle exception
}
return false;
}
This is my spring configuration:
<bean id="hibernate5AnnotatedSessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan">
<array value-type="java.lang.String">
<value>com.pointsante.dao.domaine</value>
</array>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Please can you tell me why the #Transactional on the method in the service layer is not working. Thank you.
you should probably use the HibernateTransactionManager instead of DataSourceTransactionManager.
use
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
instead of
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
also check from where the service is called. if you call it from within the service class itself, the proxy which handles the transaction management wont be used.

Hibernate using fully JavaConfig aproach in a Spring Batch Job

I have a batch job fully configured using JavaConfig. having difficulties, mainly due to little material I found on configuration using only java. In the spring batch manual itself there is no information on how to fully configure a job with spring batch using only java. I do not know if it's because this configuration model is more recent than the xml based aprouch...
Right now I'm having trouble setting up hibernate using this configuration class. I have an xml settings, but I'm not knowing how to reference it or how to change these settings for a fully "JavaConfig" version.
My job configuration class is:
#Configuration
#EnableBatchProcessing
public class CrawlerBatchConfiguration {
#Autowired
private StepBuilderFactory steps;
#Bean
public Job job(JobBuilderFactory jobs) {
return jobs.get("myJob").start(flow()).end().build();
}
protected Step step0() {
return steps.get("setupCrawlerStep").tasklet(tasklet()).build();
}
private Flow flow() {
FlowBuilder<Flow> builder = new FlowBuilder<>("flow1");
builder.start(step0())
.next(step1())
.end();
return builder.build();
}
#Bean
protected Step step1() {
return steps.get("processProductStep")
.<TransferObject, Product>chunk(10)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
#Bean
protected Tasklet tasklet() {
return new StartCrawlerTasklet();
}
#Bean
protected ProductList getProductList() {
return new ProductList();
}
#Bean
public CrawlerListener listener() {
CrawlerListener listener = new RibeiraoListener();
return listener;
}
#Bean
public ItemProcessor<TransferObject, Product> processor() {
return new ProductProcessor();
}
#Bean
public ItemReader<TransferObject> reader() {
return new ProductItemReader();
}
#Bean
public ItemWriter<Product> writer() {
return new HIbernateProductsItemWriter();
}
#Bean
public Crawler crawler() {
return new RibeiraoCrawler(new UserAgentFactory());
}
#Bean
public ProductBo productBo() {
return new ProductBoImpl();
}
#Bean
public ProductDao productDao() {
return new ProductDaoImpl();
}
}
And the hibernate config file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hbm2ddl.auto">update</prop>
<prop key="current_session_context_class">thread</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>br.com.alexpfx.supermarket.domain.Product</value>
<value>br.com.alexpfx.supermarket.domain.Manufacturer</value>
</list>
</property>
</bean>
</beans>

Spring autowiring not working, getting `applicationDao` as null

Below are my classes and xml:
#Component
#Service("ApplicationService")
public class ApplicationServiceImpl implements ApplicationService{
public ApplicationDao getApplicationDao() {
return applicationDao;
}
public void setApplicationDao(ApplicationDao applicationDao) {
this.applicationDao = applicationDao;
}
#Autowired
private ApplicationDao applicationDao;
// some methods..
}
#Service
public interface ApplicationService {
// methods...
}
#Component
#Repository("ApplicationDao")
public class ApplicationDaoImpl implements ApplicationDao {
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
// other methods...
}
public interface ApplicationDao {
// methods...
}
xml file:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven/>
<context:component-scan base-package="com" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- <property name="dataSource" ref="dataSource" /> -->
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<bean id="ApplicationDao" class="com.dao.impl.ApplicationDaoImpl"/>
<bean id="ApplicationService" class="com.service.impl.ApplicationServiceImpl"/>
Here autowiring is not working.in ApplicationServiceImpl, I am getting applicationDao as null. Have not tested sessionFactory in ApplicationDaoImpl.
I know that if I am using #Component then bean declaration in xmnl is not required.
You should not instantiate service like that..
At the time of application loading, spring container will create all instances defined in spring.xml or annotated classes and it's dependencies..
So you have to access them with the following example code..
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
ApplicationService applicationService = (ApplicationService) applicationContext.getBean("ApplicationService");
Since ApplicationService is having property that is ApplicationServiceDAOImpl, it's already been created by spring container and will return you..
But in case of directly instantiating manually by you, you are just creating instance of ApplicationService but not for ApplicationServiceDAOImpl.. so it obviously returns null
I'm currently using this approach only to access beans or services..
update for comment
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
applicationContext = arg0;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
Hope it helps,
try a change like this:
import org.springframework.beans.factory.annotation.Qualifier;
#Autowired
#Qualifier("ApplicationDao")
private ApplicationDao applicationDao;
this give spring a hint.
If you are using annotations in your application, you should denote it using a tag :
<mvc:annotation-driven />
Add this line in application context xml above component scan tag.
Also, if you are using annotations, remove ApplicationDao and ApplicationService bean declarations from xml.
And don't mark you service and dao classes with both #Component and #Service or #Repository annotations. No need to mark them #Component there. Remove it.

Mapping hibernate table entities through java configuration

How do we map hibernate table resources when we are configuring through java instead of xml config files - appreciate help.
xml-mapping for hibernate resource:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SybaseDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>/config/Stock.hbm.xml</value>
</list>
</property>
</bean>
Java-mapping?
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:persistence-sql.properties" })
#ComponentScan({......."})
public class PersistenceConfig {
#Autowired
private Environment env;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] {...... });
sessionFactory.setHibernateProperties(hibernateProperties());
(HOW DO WE INTRODUCE mappingResources HERE?)
return sessionFactory;
}
The #Entity on the model object solved the problem.
The xml configuration option had not needed this annotation.
you can edit your configuration at runtime like this:
Configuration cfg = new Configuration()
.addResource("Item.hbm.xml")
.addResource("Bid.hbm.xml");
or for class like this:
Configuration cfg = new Configuration()
.addClass(org.hibernate.auction.Item.class)
.addClass(org.hibernate.auction.Bid.class);
reference here
Here is the minimal working Hibernate+JPA setup you are interested in:
#Configuration
#EnableTransactionManagement
public class DaoConfiguration {
#Bean
public Properties hibernateProperties() {
Properties properties = new Properties();
properties.setProperty(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect");
properties.setProperty(Environment.DRIVER, "org.hsqldb.jdbcDriver");
properties.setProperty(Environment.URL, "jdbc:hsqldb:mem:testdb");
properties.setProperty(Environment.USER, "sa");
properties.setProperty(Environment.PASS, "");
properties.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "org.springframework.orm.hibernate4.SpringSessionContext");
properties.setProperty(Environment.STATEMENT_BATCH_SIZE, "30");
properties.setProperty(Environment.SHOW_SQL, "true");
properties.setProperty(Environment.HBM2DDL_AUTO, "update");
return properties;
}
#Bean
public HibernateEntityManagerFactory entityManagerFactory() {
Ejb3Configuration config = new Ejb3Configuration();
return (HibernateEntityManagerFactory) config.addProperties(hibernateProperties()).
addAnnotatedClass(User.class).
buildEntityManagerFactory();
}
#Bean
public SessionFactory sessionFactory() {
return entityManagerFactory().getSessionFactory();
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}

Resources