Spring Hibernate - Could not obtain transaction-synchronized Session for current thread - spring

I created an application with spring + hibernate, but I always get this error. This is my first application with hibernate, I read some guides but I can not solve this problem. Where am I doing wrong?
This is the code of my application
ott 05, 2014 4:03:06 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
Informazioni: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#1eab16b: startup date [Sun Oct 05 16:03:06 CEST 2014]; root of context hierarchy
ott 05, 2014 4:03:06 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
Informazioni: Loading XML bean definitions from class path resource [springConfig.xml]
ott 05, 2014 4:03:08 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
ott 05, 2014 4:03:08 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.3.6.Final}
ott 05, 2014 4:03:08 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
ott 05, 2014 4:03:08 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
ott 05, 2014 4:03:09 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
ott 05, 2014 4:03:09 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
ott 05, 2014 4:03:09 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Exception in thread "main" org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at coreservlets.StudentDAOImpl.create(StudentDAOImpl.java:19)
at coreservlets.MainApp.main(MainApp.java:14)
student.java
package coreservlets;
public class Student {
private Integer id;
private String name;
private Integer age;
public Integer getId(){return id;}//getId
public void setId(Integer id){this.id=id;}//setId
public String getName(){return name;}//getName
public void setName(String name){this.name=name;}//setName
public Integer getAge(){return age;}//getAge
public void setAge(Integer age){this.age=age;}//setAge
}//Student
studentDAO.java
package coreservlets;
import org.hibernate.SessionFactory;
public interface StudentDAO {
public void setSessionFactory(SessionFactory sessionFactory);
public void create(String name,Integer age);
}//StudentDAO
StudentDAOImpl.java
package coreservlets;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
#Repository
public class StudentDAOImpl implements StudentDAO {
private SessionFactory sessionFactory;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory=sessionFactory;
}//setSessionFactory
public void create(String name,Integer age){
Session session=sessionFactory.getCurrentSession();
Student student=new Student();
student.setName(name);
student.setAge(age);
session.save(student);
}//create
}//StudentDAOImpl
MainApp.java
package coreservlets;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("springConfig.xml");
StudentDAOImpl student=(StudentDAOImpl) context.getBean("studentDAOImpl");
student.create("Alessandro", new Integer(33));
}//main
}//MainApp
springConfig.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: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-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<context:annotation-config/>
<context:component-scan base-package="coreservlets"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_hibernate"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
<property name="initialSize" value="5"/>
<property name="maxTotal" value="10"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
</value>
</property>
</bean>
</beans>
sql
create table student
(
id integer not null auto_increment,
name varchar(20) not null,
age integer not null,
primary key(id)
);

You must enable the transaction support (<tx:annotation-driven> or #EnableTransactionManagement) and declare the transactionManager and it should work through the SessionFactory.
You must add #Transactional into your #Repository
With #Transactional in your #Repository Spring is able to apply transactional support into your repository.
Your Student class has no the #javax.persistence.* annotations how #Entity, I am assuming the Mapping Configuration for that class has been defined through XML.

I have had the same issue, but in a class that was not a part of the service layer. In my case, the transaction manager was simply obtained from the context by the getBean() method, and the class belonged to the view layer - my project utilizes OpenSessionInView technique.
The sessionFactory.getCurrentSession() method, has been causing the same exception as the author's. The solution for me was rather simple.
Session session;
try {
session = sessionFactory.getCurrentSession();
} catch (HibernateException e) {
session = sessionFactory.openSession();
}
If the getCurrentSession() method fails, the openSession() should do the trick.

Add the annotation #Transactional of spring in the class service

I had this error too because in the file where I used #Transactional annotation, I was importing the wrong class
import javax.transaction.Transactional;
Instead of javax, use
import org.springframework.transaction.annotation.Transactional;

In your xyz.DAOImpl.java
Do the following steps:
//Step-1: Set session factory
#Resource(name="sessionFactory")
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf)
{
this.sessionFactory = sf;
}
//Step-2: Try to get the current session, and catch the HibernateException exception.
//Step-3: If there are any HibernateException exception, then true to get openSession.
try
{
//Step-2: Implementation
session = sessionFactory.getCurrentSession();
}
catch (HibernateException e)
{
//Step-3: Implementation
session = sessionFactory.openSession();
}

You need to allow transaction to your DAO method.
Add,
#Transactional(readOnly = true, propagation=Propagation.NOT_SUPPORTED)
over your dao methods.
And #Transactional should be from the package:
org.springframework.transaction.annotation.Transactional

I added these configuration in web.xml and it works well for me!
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Additionally, the most ranked answer give me clues to prevent application from panic at the first run.

My configuration was like this. I had a QuartzJob , a Service Bean , and Dao . as usual it was configured with LocalSessionFactoryBean (for hibernate) , and SchedulerFactoryBean for Quartz framework. while writing the Quartz job , I by mistake annotated it with #Service , I should not have done that because I was using another strategy to wire the QuartzBean using AutowiringSpringBeanJobFactory extending SpringBeanJobFactory.
So what actually was happening is that due to Quartz Autowire , TX was getting injected to the Job Bean and at the same time Tx Context was set by virtue of #Service annotation and hence the TX was falling out of sync !!
I hope it help to those for whom above solutions really didn't solved the issue. I was using Spring 4.2.5 and Hibernate 4.0.1 ,
I see that in this thread there is a unnecessary suggestion to add #Transactional annotation to the DAO(#Repository) , that is a useless suggestion cause #Repository has all what it needs to have don't have to specially set that #transactional on DAOs , as the DAOs are called from the services which have already being injected by #Trasancational . I hope this might be helpful people who are using Quartz , Spring and Hibernate together.

My solution was (using Spring) putting the method that fails inside another method that creates and commits the transaction.
To do that I first injected the following:
#Autowired
private PlatformTransactionManager transactionManager;
And finally did this:
public void newMethod() {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus transaction = transactionManager.getTransaction(definition);
oldMethod();
transactionManager.commit(transaction);
}

#Transactional =javax.transaction.Transactional. Put it just beside #Repository.

Add transaction-manager to your <annotation-driven/> in spring-servlet.xml:
<tx:annotation-driven transaction-manager="yourTransactionBeanID"/>

Check your dao class. It must be like this:
Session session = getCurrentSession();
Query query = session.createQuery(GET_ALL);
And annotations:
#Transactional
#Repository

I encountered the same problem and finally found out that the <tx:annotaion-driven /> was not defined within the [dispatcher]-servlet.xml where component-scan element enabled #service annotated class.
Simply put <tx:annotaion-driven /> with component-scan element together, the problem disappeared.

My similar issue got fixed with below 2 approaches.
1) Through manually handling transactions:
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
UserInfo user = (UserInfo) session.get(UserInfo.class, 1);
tx.commit();
2) Tell Spring to open and manage transactions for you in your web.xml filters and Ensure to use #Repository #Transactional:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactory</param-name>
<param-value>session.factory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

In this class above #Repository just placed one more annotation #Transactional it will work. If it works reply back(Y/N):
#Repository
#Transactional
public class StudentDAOImpl implements StudentDAO

Thanks for comment of mannedear. I use springmvc and in my case I have to use as
#Repository
#Transactional
#EnableTransactionManagement
public class UserDao {
...
}
and I also add spring-context to pom.xml and it works

I had the same issue. I resolved it doing the following:
Add the this line to the dispatcher-servlet file:
<tx:annotation-driven/>
Check above <beans> section in the same file. These two lines must be present:
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation= "http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
Also make sure you added #Repository and #Transactional where you are using sessionFactory.
#Repository
#Transactional
public class ItemDaoImpl implements ItemDao {
#Autowired
private SessionFactory sessionFactory;

My Database table has mismatch column name with the Java Object (#Entity) which leads to throw the above exception.
By updating the table with appropriate column name resolves this issue.

In my case the problem was a Controller trying to access directly to a DAO with #Repository.
Adding an #Service layer on top of the #Repository fixed the problem

Related

Using #Component for bean throws error. NoSuchBeanDefinitionException

I'm trying to create a simple spring app, but when i use #Component annotation for a bean instead of defining it in spring.xml file, I'm getting this error.
Aug 09, 2017 11:06:03 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#7e32c033: startup date [Wed Aug 09 11:06:03 IST 2017]; root of context hierarchy
Aug 09, 2017 11:06:03 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'oval' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078)
at org.sumit.javabrains.DrawingApp.main(DrawingApp.java:24)
My Classes are al follows:
1. DrawingApp.java (main class)
public package org.sumit.javabrains;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DrawingApp {
public static void main(String[] args) throws InterruptedException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Oval oval = (Oval) context.getBean("oval");
oval.draw();
}
}
2. Spring.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:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="com.sumit.javabrains" />
<context:annotation-config />
<bean id="focus" class="org.sumit.javabrains.Point" scope="singleton">
<property name="x" value="-7" />
<property name="y" value="8" />
</bean>
</beans>
3 Point.java
package org.sumit.javabrains;
public class Point {
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
4 Oval.java
package org.sumit.javabrains;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
#Component
public class Oval {
private Point focus;
public Point getFocus() {
return focus;
}
#Resource
public void setFocus(Point focus) {
this.focus = focus;
}
public void draw() {
System.out.println("Point focus is: ("+focus.getX()+", "+focus.getY()+")");
}
}
could someone be able to help what caused this issue. I'm using spring 4.3.10 RELEASE
That's because your component scan is scanning the wrong packages
<context:component-scan base-package="com.sumit.javabrains" /> - Wrong
It should be scanning as follows:
<context:component-scan base-package="org.sumit.javabrains" /> - Correct
you must define all your bean in spring.xml. in this scenario you missed the Oval class in you spring configuration files. define the Oval class as a bean in your spring.xml file.
or
edit your component-scan tag and put the correct package.
Two thing went wrong here.
1. You've mentioned wrong base package in your xml file
com.sumit.javabrains must be replaced with org.sumit.javabrains
Replace #Resource with #Resource #Qualifier("focus").By default beans marked with ‘#Component’ will have the same name as the class
Try using #ComponentScan instead of #Component on top of the Oval class.
I wasn't using a spring.xml file (just the default spring boot configuration instead), my #SpringBootApplication annotated class was one package level deeper than my #Component class, which made that the #Component class wasn't picked up.
E.g.:
com.company.base/ComponentAnnotatedClass.java
com.company.base.application/MySpringBootApplication.java

Spring 4.1.5.RELEASE fails to do dependency injection for SessionFactory of Hibernate 4.3.8.Final

Question is not a duplicate as Hibernate is involved
As the James' answer partially solved the problem, I accepted it and opened a new question, please follow up here
I am trying to inject SessionFactory into a repository class; however, it looks like it does not work as the code returns NullPointer exception.
I cleaned and rebuilt the project but the issue still exist. I also put #Autowired on the setSessionFactory method but did not help.
Interface
public interface TestRep {
public void get(int id);
}
Class
#Repository
public class TestRepImpl implements TestRep{
#Autowired
SessionFactory sessionFactory;
public TestRepImpl() {
}
public TestRepImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Transactional
public void get(int id) {
String hql = "from Business where id=" + id;
Query query = sessionFactory.getCurrentSession().createQuery(hql);
....
pr-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:annotation-config/>
.....
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="TestRep" class="com.project.repository.TestRepImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
StackTrace
Mar 10, 2015 12:22:21 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [pr] in context with path [/project] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at com.project.repository.TestRepImpl.get(TestRepImpl.java:39)
at com.project.web.MainController.index(MainController.java:17)
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:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Jars
MainController
#Controller
public class MainController {
#RequestMapping("/{viewName}.htm")
public String index(#PathVariable(value = "viewName") String viewName) {
System.err.println(viewName);
Test test = new Test();
test.get(1);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
#RequestMapping("/{viewName}/{viewName2}") //suburb/catname
public String index(#PathVariable(value = "viewName") String viewName, Model model) {
System.err.println(viewName);
if (isValidView(viewName)) {
model.addAttribute("viewName",viewName);
return "page";
}
return null;
}
private boolean isValidView(String viewName) {
switch (viewName) {
case "index":
case "aboutus":
return true;
}
return false;
}
}
Test
#Service
public class Test {
public void get(int i){
TestRepImpl test = new TestRepImpl();
test.get(i);
}
}
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>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">12</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping class="com.myproject.model.MyTable" />
....
You need to use Autowiring everywhere or your program won't work. Spring can only autowire beans that are present in the Spring application context, which is what your #Controller, #Service and #Repository annotations are supposed to do. However, these annotations are meaningless without a <context:component-scan base-package="your.base.package"> tag in your config XML.
So, assuming that your controller, service and DAO are all somewhere in the package com.repository, you need to add this line to your XML config.
<context:component-scan base-package="com.repository"/>
What this does is tells Spring to recursively search inside the foo.bar.baz package (and all sub-packages) for classes annotated with #Controller, #Service, #Repository and #Component, instantiate a singleton instance of them and make them eligible to be autowired into other classes.
You also need to modify your controller and service classes to use #Autowired. Spring can't manage your classes if you instantiate them with the new keyword. These beans are singletons (only one instance of them should ever exist in your program) for a reason.
Your controller needs to change as follows.
#Controller
public class MainController {
#Autowired
private TestService testService;
#RequestMapping("/{viewName}.htm")
public String index(#PathVariable(value = "viewName") String viewName) {
System.err.println(viewName);
testService.get(1);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
#RequestMapping("/{viewName}/{viewName2}") //suburb/catname
public String index(#PathVariable(value = "viewName") String viewName, Model model) {
System.err.println(viewName);
if (isValidView(viewName)) {
model.addAttribute("viewName",viewName);
return "page";
}
return null;
}
private boolean isValidView(String viewName) {
switch (viewName) {
case "index":
case "aboutus":
return true;
}
return false;
}
}
Notice that you Autowire your service class into your controller.
Your service class needs to implement an interface. Spring does all this autowiring magic using interfaces. You cannot autowire a class that does not implement an interface, unless you specifically create an instance of that class in your XML config.
Your service class needs to change as follows:
#Service
public class TestServiceImpl implements TestService {
#Autowired
private TestRepDao testDao;
#Transactional
public void get(int i){
testDao.get(i);
}
}
and create an interface called TestService.
public interface TestService{
public void get(int i);
}
and then your DAO becomes
#Repository
public class TestRepDaoImpl implements TestRepDao{
#Autowired
private SessionFactory sessionFactory;
public void get(int id) {
String hql = "from Business where id=" + id;
Query query = sessionFactory.getCurrentSession().createQuery(hql);
}
}
which implements the interface TestRepDao:
public interface TestRepDao{
public void get(int id);
}
you can also remove the declaration of
<bean id="TestRep" class="com.project.repository.TestRepImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
from your XML configuration.
As you can see I've changed a few class names to better fit with the Spring convention. Your application is supposed to layer down from Controller to Service Class to DAO and back out again. This should work providing you follow the steps I've laid out here.
A few things to keep in mind:
Spring hates the new keyword. If you find yourself using it, you are probably doing something wrong.
There is only ever one instance of any of your classes that Spring picks up with the component scan in your entire application. DO NOT use these classes to store persistent data or states. That path is full of threading issues, race conditions and pits full of acid spiders.
Read and re-read the documentation, these are not easy concepts to pick up if you have never used Spring before. Spring is super easy to use, once you understand how it works, and how it expects you to use it.
Spring works on interfaces. If your class doesn't implement an interface, Spring can't proxy it without using AspectJ Load Time Weaving, which is a conversation for another day, and not something you should be using, just starting out. If you don't know why Spring needs to create a proxy of your object, you need to re-read the documentation until you understand the application context.
I moved the #Transactional annotation into the Service class. This is because the DAO should only be concerned with accessing and retrieving the data from the database, NOT having to manage the connection/session to the database, that is the job of the service class.
I'm guessing you started using the new keyword after hitting exceptions saying something similar to
No qualifying bean of type found for dependency TestService.
This is Spring telling you that it doesn't have a bean that can be autowired into the TestService field on whatever class. Listen when Spring is telling you things, it will save you a lot of bother.
Don't be discouraged, I faced all these problems when I was trying to learn how to use Spring, but I got through it and Spring is second nature to me now.

Spring context:component-scan not working with annotated beans

I'm trying to run a simple Spring + Hibernate tutorial => Maven Spring Hibernate annotation example
My beans definition file BeanLocations.xml is like this :
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Database Configuration -->
<import resource="../database/Datasource.xml"/>
<import resource="../database/Hibernate.xml" />
<context:component-scan base-package="com.sample.springhibernate"/>
</beans>
My main method:
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext("classpath*:BeanLocations.xml");
StockBo stockBo = (StockBo)appContext.getBean("stockBo");
}
I have a defined service with an interface:
public interface StockBo {
public void save(Stock stock);
public void update(Stock stock);
public void delete(Stock stock);
public Stock findByStockCode(String stockCode);
}
And his implementation:
#Service("stockBo")
public class StockBoImpl implements StockBo {
#Autowired
StockDao stockDao;
public void setStockDao(StockDao stockDao){
this.stockDao = stockDao;
}
#Override
public void save(Stock stock) {
stockDao.save(stock);
}
........
There is any problem with this because spring throws a Exception when StockBo)appContext.getBean("stockBo") :
30-oct-2014 15:31:49 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#64dc11: display name [org.springframework.context.support.ClassPathXmlApplicationContext#64dc11]; startup date [Thu Oct 30 15:31:49 CET 2014]; root of context hierarchy
30-oct-2014 15:31:49 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext#64dc11]: org.springframework.beans.factory.support.DefaultListableBeanFactory#a3d4cf
30-oct-2014 15:31:49 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#a3d4cf: defining beans []; root of factory hierarchy
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'stockBo' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:387)
Spring not foud my annotated service StockBoo (with #Service("stockBo") )....
What is the problem? How can I ensure that Spring recognize my service with component scan?
FYI: StockBo is in com.sample.springhibernate.bo and StockBoImpl in com.sample.springhibernate.bo.impl
If you turn your log level to DEBUG, you'll more than likely find a line like
DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 0 bean definitions from location pattern [classpath*:BeanLocations.xml]
That is, your ClassPathXmlApplicationContext did not find any resources that match classpath*:BeanLocations.xml and therefore didn't load any context.
You'll need to provide a resource location String value that properly identifies and locates the context configuration file.

SimpleJdbcTemplate not serializable

I use JSF and Spring. The JSF beans must be serializable by design. The JSF beans get injected with Spring beans that handle the db access. Thus these beans must be serializable as well. However simpleJdbcTemplate is not serializable so I get stack traces when restarting the servlet and sessions are lost. If I declare simpleJdbcTemplate to be transient, I don't get stack traces about "not serializable" but then simpleJdbcTemplate is sometimes NULL after a restart, which is even worse.
So what can I do so that the spring beans get injected with a "fresh" simpleJdbcTemplate when the servlet is restarted?
The classes look like this:
#Repository
public class Users implements Serializable
{
#Autowired
private SimpleJdbcTemplate simpleJdbcTemplate;
// ...
}
#ManagedBean
#SessionScoped
public class ThisBean implements Serializable
{
#ManagedProperty(value = "#{users}")
private Users users;
public void setUsers(Users users)
{
this.users = users;
}
// ...
}
Now some config files, just so that you see I didn't miss something standard.
The web.xml has this:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>Listeners.SessionListener</listener-class>
</listener>
The applicationContext.xml has this:
<context:annotation-config />
<context:component-scan base-package="SpringDB"/>
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/mysql"/>
<bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg>
<ref bean="dataSource"/>
</constructor-arg>
</bean>
faces-config.xml has this:
<application>
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
<application>
<message-bundle>jsf</message-bundle>
</application>
</application>
Why don't you try to pass in the DataSource reference instead of the JdbcTemplate. The common practice is to inject the data source and create the JdbcTemplate within the setter for the data source. You'll find the following example in the spring documentation:
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
You can also use #Autowired on the setDataSource method if you don't want to set up your beans with XML. For further details have a look at the JdbcTemplate best practices section of the excellent spring documentation.
Add scope="prototype" definition for simpleJDBCTemplate bean. Then Spring Framework will create new instance for every servlet instance. More info about bean scopes: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes

Spring setting WebApplicationContext in ServletContextAware bean

I'm converting existing code to Spring 3 JDBC. I've put it into a class (SpringDB.Users) that implements ServletContextAware. In setServletContext(), the following code doesn't work:
public void setServletContext(ServletContext sc)
{
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
simpleJdbcTemplate = (SimpleJdbcTemplate) wac.getBean("simpleJdbcTemplate");
}
The reason is: exception is java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
However I did register a ContextLoaderListener in web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
The applicationContext.xml has this:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/mysql"/>
<bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg>
<ref bean="dataSource"/>
</constructor-arg>
</bean>
<bean class="SpringDB.Users"/>
which results in getting the call to setServletContext(). The class SpringDB.Users is mostly static stuff. It is never instantiated by the java code.
Apparently, the call to WebApplicationContextUtils.getRequiredWebApplicationContext() is "too early". Because what does work without any trouble is to get the WebApplicationContext at a later time, i.e. when database work really starts - so what I do is to call a private function getSimpleJdbcTemplate() instead of a private variable simpleJdbcTemplate:
static private SimpleJdbcTemplate getSimpleJdbcTemplate ()
{
if (simpleJdbcTemplate == null)
{
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
simpleJdbcTemplate = (SimpleJdbcTemplate) wac.getBean("simpleJdbcTemplate");
}
return simpleJdbcTemplate;
}
Is there any solution so that the variable simpleJdbcTemplate can be initialized within setServletContext() ?
Am I missing something obvious, or just expecting too much?
Why do you need that in the first place?
If your class is a bean, then you can simply inject (with #Inject, #Autowired or xml) the jdbc template:
#Inject
private SimpleJdbcTemplate template;

Resources