I have problem with open session. First of all I use Spring 4.0 + JSF 2.2 + Hibernate 4.3. To provide open session I use org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.
It works partially, I get some entities from database, render the view and lazy loading works correct.
However when after rendering a view I use pagination in p:dataGrid I get lazy initialization exception. How Can I avoid that? I would like that the object will be connected to session as long as the management bean lives. How can I make pagination works without lazy initialization error?
To resolve this problem I try to use check what happen i my management bean. I don't know if I understand it correct but when I use the view scope bean I though that all the time it should be one thread that deal with this bean. But when I print thread id it looks that for every request tomcat use new thread. It's correct behavior? Before, without using spring I use standard open session in view filter and I set hibernate.current_session_context_class to org.hibernate.context.ThreadLocalSessionContext and everything works perfect. I try to use the same setting here but it cause many errors and I read that when I use filter provided by spring I shouldn't mess with it. I use Tomcat 7.0.34 and hibernate-c3p0 4.3.
Part of web.xml
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Hibernate configuration:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>system.properties</value>
</property>
</bean>
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- c3p0 props-->
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
<property name="maxStatements" value ="${c3p0.maxStatements}" />
</bean>
<!-- Hibernate session factory -->
<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.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.validator.apply_to_ddl">false</prop>
</props>
</property>
<property name="packagesToScan" value="com.efsf.ostoja" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Managed bean:
package com.efsf.ostoja.clientCase.view;
import com.efsf.ostoja.clientCase.logic.interfaces.ICaseService;
import com.efsf.ostoja.clientCase.model.ClientCase;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import lombok.Getter;
import lombok.Setter;
#ViewScoped
#ManagedBean
public class MarketMB implements Serializable{
#Getter #Setter
private List<ClientCase> cases;
#ManagedProperty(value = "#{caseService}")
#Getter #Setter
private ICaseService service;
#PostConstruct
public void init(){
cases=service.getAllActiveCases();
System.out.println("Id: "+Thread.currentThread().getId());
}
public void test(){
System.out.println("Id2: "+Thread.currentThread().getId());
}
}
Method from service:
#Override
#Transactional
public List<ClientCase> getAllActiveCases(){
return clientCaseDao.findAllByProperty("status", CaseStatus.NEW);
}
Part of my view:
<h:form>
<p:dataGrid value="#{marketMB.cases}" var="c" id="paginatorTable" styleClass="simplePagination" paginator="true" rows="5" columns="1" paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}">
//some div with data here
</p:dataGrid>
</h:form>
Related
web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
my spring-mvc-servlet.xml
<context:component-scan base-package="org.app.controller" />
<mvc:resources mapping="/resources/**" location="/WEB-INF/resources/" />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
my controller: Just for illustration
#Controller
public class HomeController {
LoginService loginService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String login(Model model) {
loginService.checkLoginDetails(new LoginDetails("Svn", 1));
return "login";
}
AppplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- <context:annotation-config /> -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
<bean class="org.app.controller.HomeController" autowire="byName"></bean>
<bean id="loginDAO" class="org.app.DAOImpl.LoginDAOImpl" autowire="byName"></bean>
<bean id="loginService" class="org.app.DAOServiceImpl.LoginServiceImpl" autowire="byName"></bean>
<bean id="employeeDAO" class="org.app.DAOImpl.EmployeeDAOImpl" autowire="byName"></bean>
<bean id="employeeService" class="org.app.DAOServiceImpl.EmployeeDAOServiceImpl" autowire="byName"></bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="annotatedClasses">
<list>
<value>org.app.entity.Employee</value>
<value>org.app.entity.LoginDetails</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- <context:component-scan base-package="org.infy"> <context:exclude-filter
expression="org.springframework.stereotype.Controller" type="annotation"
/> </context:component-scan> -->
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
LoginServiceImpl
public class LoginServiceImpl implements LoginService{
LoginDAO loginDAO;
#Override
#Transactional
public boolean checkLoginDetails(LoginDetails loginDetails) {
return loginDAO.checkLoginDetails(loginDetails);
}
}
Problem: My LoginDAO is null. Spring is not able to instantiate it's object using auto-wiring when done without annotation, however, works fine when I use it with annotation along with appropriate changes in ApplicationContext.xml.
My LoginService bean is getting instantiated by the component scan of dispatcher servlet context. Now when instantiating LoginServiceImpl spring should look into RootApplication context for other bean definitions however it doesn't.
I don't understand why does this happen when using #autowire with or enabling the component scan. it works fine then why not without annotation.
I'm also not sure what I'm trying to do. I was playing with Spring MVC and got stuck on this.
Please update your ApplicationContext.xml
<bean id="loginService" class="org.app.DAOServiceImpl.LoginServiceImpl" autowire="byName">
<property name="loginDAO" ref="loginDAO"> </property>
</bean>
Same thing goes for the EmployeeService and your controller as well.
<bean class="org.app.controller.HomeController" autowire="byName">
<property name="loginService" ref="loginService"> </property>
</bean>
<bean id="employeeService" class="org.app.DAOServiceImpl.EmployeeDAOServiceImpl" autowire="byName">
<property name="employeeDAO" ref="employeeDAO"> </property>
</bean>
Though I still recommend you to use annotations.
In AppplicationContext.xml you need to specify injected dependencies for your beans as element inside
I have a problem with EntityManager. When I try to use EntityManager in a dao class, I got null pointer exception. So EntityManager is not injected despite #PersistenceContext annotation.
My dao:
package com.fido.pia.dao;
import com.fido.pia.model.User;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Repository
public class UserDao {
#PersistenceContext
protected EntityManager entityManager;
public User save(User row) {
if(row.isNew()) {
entityManager.persist(row);
return row;
} else {
return entityManager.merge(row);
}
}
}
Servlet Config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--
Adds some default beans (HandlerAdapter, HandlerMapping, Binding Initializer...). It also turn on some annotations.
Explanation in http://stackoverflow.com/questions/28851306/spring-framework-what-is-the-purpose-of-mvcannotation-driven
WITHOUT THIS, #RequestMapping ANNOTATIONS ARE LOADED, BUT MAPPING DO NOT WORK!!
-->
<mvc:annotation-driven />
<!-- Set loading annotations from classes
<context:component-scan base-package="com.fido.pia"/>-->
<!--manual homepage-->
<mvc:view-controller path="/" view-name="home"/>
<!--view resolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<!--static resources - request will be handeled by ResourceHttpRequestHandler-->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!--database config-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/pia" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!--entity manager factory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.fido.pia" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--<property name="generateDdl" value="true" />-->
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!--Set loading annotations from classes-->
<context:component-scan base-package="com.fido.pia"/>
</beans>
Any ideas what is wrong here?
In entityManagerFactory bean definition, try this :
<property name="packagesToScan" value="com.fido.pia.*" />
This should work
I finally solve it. The problem was that I use common dependency injection to inject my dao class in controller. When I change it to DI with autowired (added #autowired to controller constructor), entity manager in dao is initialized.
So now it works, but I'm still curious about why is that change so important. I've asked new question about it.
You need to enable persistence annotations:
<context:annotation-config/>
or
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
I use spring 3.2.8, hibernate 4. I have an error "org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: createCriteria is not valid without active transaction"
web.xml:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>journeys</display-name>
<servlet>
<servlet-name>journeys</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>journeys</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/journeys-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
</jsp-config>
</web-app>
journeys-servlet.xml:
<beans xmlns="...">
<context:annotation-config />
<context:component-scan base-package="journeys.*" />
<bean id="viewResolver"
...
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://myserver:3306/name" />
<property name="username" value="user" />
<property name="password" value="password" />
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:annotation-driven />
</beans>
class/hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Mapping files -->
<mapping class="journeys.entity.Company"/>
....
</session-factory>
</hibernate-configuration>
CompanyDAO:
package journeys.dao;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import journeys.utils.Pair;
import journeys.entity.Company;
import journeys.entity.Journey;
import journeys.entity.JourneyDeparture;
import journeys.entity.Order;
#Component
public class CompanyDAO extends AbstractDAO<Company> {
#Autowired
private SessionFactory sessionFactory;
public CompanyDAO() {
super(Company.class);
}
#Transactional
#SuppressWarnings("unchecked")
public List<Company> f() {
return (List<Company>)sessionFactory.getCurrentSession().createCriteria(Company.class).list();
}
}
CompanyController:
package journeys.controller;
import journeys.dao.CompanyDAO;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller
#RequestMapping(value = "/company")
public class CompanyController {
#Autowired
CompanyDAO companydao;
#RequestMapping(value = {"", "/", "list"}, method = RequestMethod.GET)
public ModelAndView list() {
ModelAndView model = new ModelAndView("Company/list");
model.addObject("companies", companydao.f());
return model;
}
}
Do the following and the problem goes away:
In your hibernate.cfg.xml add the following property:
<property name="hibernate.current_session_context_class"> org.springframework.orm.hibernate4.SpringSessionContext
</property>
Also remove the line <property name="current_session_context_class">thread</property> that you currently have in your code
A common reason for this that I have seen is the lack of "engine" to apply the effect of #Transactional. Namely, in your pom you need to have a runtime dependency either on cglib or jaspect. Seeing how your tx-manager is defined, it seems you are likely to need cglib.
Edit:
Also, to enable cglib, use:
<tx:annotation-driven proxy-target-class="true" transaction-manager="txManager"/>
instead of just
<tx:annotation-driven transaction-manager="txManager" />
I am attempting to split out the Hibernate DAO and Model Object layer from an existing application so they can be used across multiple applications. Unfortunately, I'm not having much success: a NoSuchBeanDefinitionException is thrown when trying to get the SessionFactory from the Application Context.
All of DAO classes extend a class called GenericDaoHibernate2. Each DAO extends this, and passes a Class in the constructor. Pretty standard Generic DAO stuff.
I figured this would be the logical place to set the session factory as well (there are ALOT of DAO classes). So, in the constructor class, I did this:
public GenericDaoHibernate2(final Class<T> persistentClass) {
ctx = new ClassPathXmlApplicationContext("META-INF/applicationContext-dao.xml");
this.sessionFactory = (SessionFactory) ctx.getBean(SessionFactory.class);
log.debug("Value of app context: " + ctx.toString());
log.debug("Value of sessionFactory: " + sessionFactory);
this.persistentClass = persistentClass;
}
Unfortunately, this blew up with the previously mentioned exception:
Caused By: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] 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:924)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:793)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:551)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
Truncated. see log file for complete stacktrace
I've also attempted this with the app context file just in the classpath, setting the value when declaring the variable, etc, etc.
I'm guessing what is happing is that as part of the Maven build, the jar isn't referencing the libraries on the classpath, but I really don't know...
UPDATE: Stupid, stupid me... forgot to show the application context file.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
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-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"
default-lazy-init="true">
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="org.jason.dao.hibernate" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#//192.168.1.1/db01" />
<property name="username" value="USER" />
<property name="password" value="PASSWORD" />
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibername.format_sql">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.use_get_generated_keys">true</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.default_catalog">CATALOG</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>org.jason.model</value>
</list>
</property>
</bean>
</beans>
Another update: Was asked for a sample DAO. The interface is a "standard" generic interface, accepting the generic paramters T and PK, just like the Impl. The following one doesn't have any specific methods other than what it inherits from GenericDaoHibernate2.
#Repository("AreaOfPreferenceDAO")
public class HibernateAreaOfPreferenceDAO extends GenericDaoHibernate2<AreaOfPreference, AreaOfPreferenceCompositeId> implements AreaOfPreferenceDAO {
public HibernateAreaOfPreferenceDAO()
{
super(AreaOfPreference.class);
}
}
In order to wire in the SessionFactory into your custom generic DAO, you can go ahead and simply use #Autowire, as long as the overall Spring context is defining the SessionFactory bean.
To define the bean:
<bean id="sessionFactory" class=
"org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.rest" />
<property name="hibernateProperties">
...
</property>
</bean>
<bean id="dataSource" class=
"org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="restUser" />
<property name="password" value="restmy5ql" />
</bean>
And to wire, simply:
#Autowired
SessionFactory sessionFactory;
The right place to bootstrap the context is not in the constructor of your DAO; if you're working with a web application, you can go with the traditional approach:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Since this is not a web application, then the context cannot be bootstrapped in web.xml; however, the bootstrapping still needs to be external - a main class would simply need to create the XmlWebApplicationContext and configure it.
Hope this helps.
The fact that you are creating a new application context in each DAO object may be getting you into trouble.
ctx = new ClassPathXmlApplicationContext("META-INF/applicationContext-dao.xml");
This is kind of circular if you think about it. You call the context, which does a component scan for DAO's, then the DAO instantiates a new context, which does a component scan for DAO's ...
I would just autowire the sessionfactory directly as someone else had mentioned.
#Repository("AreaOfPreferenceDAO")
public class HibernateAreaOfPreferenceDAO extends GenericDaoHibernate2<AreaOfPreference, AreaOfPreferenceCompositeId> implements AreaOfPreferenceDAO {
#Autowired
public HibernateAreaOfPreferenceDAO(SessionFactory sessionFactory)
{
super(sessionFactory, AreaOfPreference.class);
}
}
No component should need to construct a new application context.
Had the same problem, unable to make injection work.
My problem was "sequence". Hibernate xml must be invoked first.
dispatcher-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- init hibernate first -->
<import resource="classpath:HibernateContext.xml"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:annotation-driven />
<context:component-scan base-package="com.xxx.yyy" />
content of hibernateContext.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:database.properties</value>
</list>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.xxx.yyy.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- bean id="transactionManager" class=" org.springframework.transaction.jta.JtaTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean-->
I'm trying to create a persistance project so it can be re-used by some other projects I'm building on top. I.e it will be used by a web service/spring mvc project and by standalone jar which does some file processing.
I've used hibernate with spring mvc before but never as a standalone executable java jar so I have everything setup and working(application context) :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- Enable annotation style of managing transactions -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- HIBERNATE -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:spring.properties" />
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.databaseurl}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="acquireIncrement" value="5" />
<property name="idleConnectionTestPeriod" value="60"/>
<property name="maxPoolSize" value="100"/>
<property name="maxStatements" value="50"/>
<property name="minPoolSize" value="10"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list> <value>com/project/utility/persistence/mapping/TestProp.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- END HIBERNATE -->
</beans>
When I test it from main class everything looks ok with mapping/dependencies :
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("appCtx.xml");
}
What I want to do next is to build few dao classes which will get some data and I'd build some interface above that so it can be re-used by both webservice and processing tool as a jar(maven dependency).
In order to build dao classes I need sessionFactory to be != null always. How do I do this?
There are many approaches to this. One solution I use is to use the javax.persistence.PersistenceContext annotation. Spring will respect this annotation and inject a proxy to a thread local EntityManager. Provided your DAO is created by Spring this allows access to the entity manager from within your DAO.
public class DAO {
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
#Repository
public class MyDAO {
#Autowired
private SessionFactory sessionFactory;
// ...
}
and add the MyDAO bean to the context XML file, or simply add the following lines to this file:
<context:annotation-config />
<context:component-scan base-package="one.of.the.parent.packages.of.your.dao" />