Spring #Autowired not working (not always) - spring

I have some problems with autowire annotation in one of my services. I have spent a lot of hours to find a solution but I don't have idea what I'm doing wrong. My app looks like this.
Here is my controller:
package control.peso.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import control.peso.data.ResumenMedicionPeso;
import control.peso.service.HomeService;
#Controller
public class HomeController {
#Autowired
private HomeService homeService; //NOPMD
#RequestMapping(value = "json/resumen_mediciones.action")
#ResponseBody
public final ResumenMedicionPeso
dataJsonPeso(final HttpServletRequest req) {
final ResumenMedicionPeso peso = homeService.getResumenMediciones();
return peso;
}
}
My service layer:
package control.peso.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import control.peso.dao.PesoDAO;
import control.peso.data.ResumenMedicionPeso;
#Service
#Transactional(readOnly = true)
public class HomeService {
#Autowired
private PesoDAO pesoDAO; //NOPMD
public final ResumenMedicionPeso getResumenMediciones() {
final ResumenMedicionPeso resumMedicionPeso = new ResumenMedicionPeso();
resumMedicionPeso.setMaxPeso(pesoDAO.getMaxPeso());
resumMedicionPeso.setMinPeso(pesoDAO.getMinPeso());
resumMedicionPeso.setMaxGrasa(pesoDAO.getMaxGrasa());
resumMedicionPeso.setMinGrasa(pesoDAO.getMinGrasa());
resumMedicionPeso.setMaxPorcenGrasa(pesoDAO.getMaxPorcenGrasa());
resumMedicionPeso.setMinPorcenGrasa(pesoDAO.getMinPorcenGrasa());
resumMedicionPeso.setMaxMusculo(pesoDAO.getMaxMusculo());
resumMedicionPeso.setMinMusculo(pesoDAO.getMinMusculo());
resumMedicionPeso.setMaxPorcenMusculo(pesoDAO.getMaxPorcenMusculo());
resumMedicionPeso.setMinPorcenMusculo(pesoDAO.getMinPorcenMusculo());
return resumMedicionPeso;
}
}
My dao:
package control.peso.dao;
import java.util.List;
import org.hibernate.SessionFactory;
import control.peso.model.MedicionPeso;
public class PesoDAO implements IPesoDAO {
private SessionFactory sessionFactory;
public final SessionFactory getSessionFactory() {
return sessionFactory;
}
public final void setSessionFactory(
final SessionFactory pSessionFactory) {
this.sessionFactory = pSessionFactory;
}
#Override
public final void addPeso(final MedicionPeso peso) {
getSessionFactory().getCurrentSession().save(peso); //NOPMD
}
#Override
public final void updatePeso(final MedicionPeso peso) {
getSessionFactory().getCurrentSession().update(peso); //NOPMD
}
#Override
public final void deletePeso(final Integer idPeso) {
getSessionFactory().getCurrentSession()
.delete(new MedicionPeso(idPeso));
}
#Override
public final MedicionPeso getPesoById(final Integer idPeso) {
#SuppressWarnings("unchecked") //NOPMD
final List<MedicionPeso> list = getSessionFactory() // NOPMD
.getCurrentSession()
.createQuery("from MedicionPeso where idPeso = ?")
.setParameter(0, idPeso).list();
return list.get(0); //NOPMD
}
#Override
public final List<MedicionPeso> getPesos() {
#SuppressWarnings("unchecked")
final List<MedicionPeso> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("from MedicionPeso medicionPeso "
+ "order by medicionPeso.fechaMedicion desc")
.list();
return list;
}
public final Float getMaxPeso() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select max(peso) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMinPeso() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select min(peso) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMaxGrasa() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select max(pesoGrasa) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMinGrasa() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select min(pesoGrasa) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMaxPorcenGrasa() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select max(pesoGrasa) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMinPorcenGrasa() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select min(porcentajeGrasa) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
/**
* Recupera la medicion de musculo con valor maximo.
* #return El valor maximo de las mediciones de musculo.
*/
public final Float getMaxMusculo() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select max(porcentajeGrasa) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMinMusculo() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select min(pesoMusculo) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMaxPorcenMusculo() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select max(porcentajeMusculo) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
public final Float getMinPorcenMusculo() {
#SuppressWarnings("unchecked")
final List<Float> list = getSessionFactory() //NOPMD
.getCurrentSession()
.createQuery("select max(porcentajeMusculo) from MedicionPeso")
.list();
return (Float) list.get(0); //NOPMD
}
}
My dao interface:
package control.peso.dao;
import java.util.List;
import control.peso.model.MedicionPeso;
public interface IPesoDAO {
void addPeso(MedicionPeso peso);
void updatePeso(MedicionPeso peso);
void deletePeso(Integer idPeso);
MedicionPeso getPesoById(Integer idPeso);
List<MedicionPeso> getPesos();
}
This is my 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:mvc="http://www.springframework.org/schema/mvc"
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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!--Routes -->
<mvc:view-controller path="/" view-name="home"/>
<mvc:view-controller path="/home" view-name="home"/>
<mvc:view-controller path="/medicion" view-name="medicion_peso"/>
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="control.peso" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<!-- misc -->
<!--
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
-->
<!-- Tiles Resolver -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.tiles2.TilesView
</value>
</property>
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
<!-- Application Message Bundle -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<!-- JSON Objets Definition -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
<!-- Beans Declaration -->
<bean id="MedicionPeso" class="control.peso.model.MedicionPeso" />
<!-- User DAO Declaration -->
<bean id="PesoDAO" class="control.peso.dao.PesoDAO">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
<!-- Data Source Declaration -->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/juan" />
<property name="user" value="root" />
<property name="password" value="" />
<property name="maxPoolSize" value="10" />
<property name="maxStatements" value="0" />
<property name="minPoolSize" value="5" />
</bean>
<!-- Session Factory Declaration -->
<bean id="SessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="DataSource" />
<property name="annotatedClasses">
<list>
<value>control.peso.model.MedicionPeso</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager" />
<!-- Transaction Manager is defined -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
</beans>
So when I launch my web-app, my controller Autowires correctly the service, but my DAO object in my service has null value (not injected properly).
Any ideas?
It's curious because from another service, the same DAO is properly injected.
Thanks

in your HomeService, you've specified the implementation of IPesoDAO, not the interface. try changing it to IPesoDAO instead and see if that helps.
in addition, you may also want to create an interface IHomeService and have your existing HomeService implement it, again, changing the controller to reference the interface, not the implementation

Main thing to grasp is that your service is #Transactional that means that Spring will have to create transactional proxy around it. It is a separate object that is injected instead of bean, that will delegate all its method calls to the original bean, opening and closing transactions before and after.
As incomplete-co.de has suggested your service is injected as class, and not as interface.
The only way to automatically create a separate proxy object in this case is to subclass your original service class HomeService. If everything would go normal than a subclass would be created:
The first notable side effect will be that the constructor of HomeService would be called twice - because in Java you are forced to call the constructor of super class, so the constructor of the proxy will call the constructor of HomeService in addition to the construction of the bean itself.
The second effect will be that the subclass in Java inherits all the base fields of the superclass, they are not initialized, i.e. pesoDAO reference of the proxy instance will be null. It's okay because field values are not needed for proxy, because it will call the method of original bean, which fields are initialized.
The third thing is that this scheme will work only if the methods of the super class are not declared final.
In your case when the method of proxy is called instead of delegating the call to original bean it behaves as the superclass but with its fields left uninitialized.
So I recommend to follow incomplete-co.de advice and inject the service as interface, interfaces are more suitable for proxying because the proxying framework don't have to fight with the subclassing restrictions.
P.S. another minor restriction is that in subclassing the framework will need to have a strategy to decide which inherited constructor to call - in Spring/CGLIB the parameterless constructor is preferred, so you will be forced to create one if the compiler did not do this automatically.
So these are some practical reasons(I'm not mentioning good OOD principles here) why in Spring we are offen forced to to inject services as interfaces.

You have a strange mix of annotation based and XML based beans declaration, which makes code not clear - it is really better to use annotations as much as possible and use XML configuration only for specific stuff (datasources, jpa related stuff, third party beans).
Use of #Autowired alone is also misleading - in this case Spring will try to find bean named as your annotated class member.
In your particular case you declare DAO bean in XML as:
<!-- User DAO Declaration -->
<bean id="PesoDAO" class="control.peso.dao.PesoDAO">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
And then you are trying to inject it as:
#Service
#Transactional(readOnly = true)
public class HomeService {
#Autowired
private PesoDAO pesoDAO; //NOPMD
}
This will likely cause injection failure since Spring will try to find bean named as 'pesoDao' (this is default naming convention), but you have 'PesoDao' in XML.
To resolve this as well as never worry of such issues further, you can explicitly name your annotated beans and also explicitly provide this name when autowiring (use #Qualifier annotation).
Example:
#Component("pesoDao")
public class PesoDAO implements IPesoDAO {
private SessionFactory sessionFactory;
}
#Service("homeService")
#Transactional(readOnly = true)
public class HomeService {
#Autowired
#Qualifier("pesoDao")
private PesoDAO pesoDAO; //NOPMD
}
In this case, you always know what is going to be injected.

Related

Unable to insert record into DB using hibernate integrated with Spring using XML

I am trying to implement a signup page using Spring MVC integrated with hibernate using XML.
Application Context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
xmlns:tx="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe"></property>
<property name="username" value="hr"></property>
<property name="password" value="umashetti123"></property>
</bean>
<bean id="mysessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingResources">
<list>
<value>Login_Detailshbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="checkWriteOperation" >false</prop>
</props>
</property>
</bean>
<bean id="template" class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="mysessionFactory"></property>
<property name="checkWriteOperations" value="false"></property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="mysessionFactory" />
</bean>
<bean id="d" class="com.uday.Login_DetailsDao">
<property name="template" ref="template"></property>
</bean>
</beans>
Controller Class
package com.uday;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
public class ControllerSignUp_Login {
public ControllerSignUp_Login() {
// TODO Auto-generated constructor stub
}
#RequestMapping("/hello")
public String diaplay(#RequestParam("name") String name, #RequestParam("pass") String pass,Model m) {
Login_DetailsDao dao = (Login_DetailsDao) getBean();
if(dao.isLogoinSuccessfull(name , pass)) {
m.addAttribute("message", "Hello"+name);
return "Success";
}
else {
m.addAttribute("message", "You have Entered Wrong pin");
return "Failure";
}
}
#RequestMapping("/SignUp")
public String redirect() {
System.out.println("ControllerSignUp_Login.display()");
return "signup";
}
#RequestMapping("/login")
public String display() {
System.out.println("ControllerSignUp_Login.display()");
return "login";
}
#RequestMapping("/updateDetails")
#Transactional
public String display(HttpServletRequest req , Model M) {
String firstName=req.getParameter("firstName");
String lastName=req.getParameter("lastName");
String mobileNo=req.getParameter("mobileNo");
String address=req.getParameter("address");
String city=req.getParameter("city");
String password=req.getParameter("password");
Login_DetailsDao dao = (Login_DetailsDao) getBean();
if(checkLength(firstName) && checkLength(lastName) && checkLength(mobileNo) && checkLength(address) && checkLength(city) && checkLength(password)) {
Login_Details ld = new Login_Details();
ld.setFirstName(firstName);
ld.setLastName(lastName);
ld.setCity(city);
ld.setAddress(address);
ld.setMobileNo(mobileNo);
ld.setPassword(password);
dao.saveEmployee(ld);
M.addAttribute("message", "SignUp Successfull !! Thank You");
M.addAttribute("displayLogin", true);
return "Success";
}
else {
M.addAttribute("message","SignUp Failed !! All details are mandatory.");
return "signup";
}
}
public boolean checkLength(String s) {
if(s != null && s.length() > 0) {
return true;
}
return false;
}
public Object getBean() {
ApplicationContext appcontext = new ClassPathXmlApplicationContext("Applicationcontext.xml");
Login_DetailsDao lDDao =(Login_DetailsDao)appcontext.getBean("d");
return lDDao;
}
}
DAO class
package com.uday;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.transaction.annotation.Transactional;
public class Login_DetailsDao {
HibernateTemplate template;
HibernateTransactionManager hbt;
public HibernateTransactionManager getHbt() {
return hbt;
}
public void setHbt(HibernateTransactionManager hbt) {
this.hbt = hbt;
}
public Login_DetailsDao() {
// TODO Auto-generated constructor stub
}
#Transactional
public void saveEmployee(Login_Details e){
System.out.println("Login_DetailsDao.saveEmployee()"+e.getMobileNo());
SessionFactory sf = hbt.getSessionFactory();
Session session =sf.getCurrentSession();
Transaction t =session.beginTransaction();
session.persist(e);
t.commit();
session.close();
}
public void setTemplate(HibernateTemplate template) {
this.template = template;
}
public List<Login_Details> getEmployees(){
List<Login_Details> list=new ArrayList<Login_Details>();
list=template.loadAll(Login_Details.class);
return list;
}
}
I am able to get the login_details data but unable to insert the record.
getting below exception
org.xml.sax.SAXParseException; lineNumber: 51; columnNumber: 29; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'tx:annotation-driven'.
Could any one please suggest to solve this?
Your code is flawed on multiple levels.
Never create a BeanFactory or ApplicationContext just because you need an instance of a bean. Instead use dependency injecting for that bean.
The fact that you use a BeanFactory over an ApplicationContext is one of the reasons your code doesn't work. See this for why you shouldn't use a BeanFactory.
You aren't using transactions and without transactions nothing will be persisted in the database.
Now first in your controller you need to dependency inject the Login_DetailsDao instead of creating a BeanFactory and obtain an instance.
#Controller
public class ControllerSignUp_Login {
private final Login_DetailsDao dao;
#Autowired // If using Spring 4.3 or later this isn't needed
public ControllerSignUp_Login(Login_DetailsDao dao) {
this.dao=dao;
}
}
Now in your method use this instance, instead of doing the lookup.
Your Login_DetailsDao should operate on the SessionFactory and nothing else.
public class Login_DetailsDao {
private final SessionFactory sf;
public Login_DetailsDao(SessionFactory sf) {\
this.sf=sf;
}
#Transactional
public void saveEmployee(Login_Details e){
sf.getCurrentSession().save(e);
}
#Transactional(readOnly=true)
public List<Login_Details> getEmployees(){
return sf.getCurrentSession()
.createQuery("SELECT ld FROM Login_Details", Login_Details.class)
.getResult();
}
}
That is all you need. Now finally in your XML tie all this together.
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
xmlns:tx="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe"></property>
<property name="username" value="hr"></property>
<property name="password" value="umashetti123"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingResources">
<list>
<value>Login_Detailshbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="checkWriteOperation" >false</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="d" class="com.uday.Login_DetailsDao">
<constructor-arg ref="sessionFactory" />
</bean>
</beans>
One simple change made this application worked.
1 > Deleted applicationcontext.xml and added the contents in disapatcher-servlet.xml
disaptcher-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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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-3.0.xsd">
<context:annotation-config/>
<tx:annotation-driven />
<!-- Provide support for component scanning -->
<context:component-scan base-package="com.uday" />
<!--Provide support for conversion, formatting and validation -->
<mvc:annotation-driven/>
<!-- Define Spring MVC view resolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe"></property>
<property name="username" value="hr"></property>
<property name="password" value="umashetti123"></property>
</bean>
<bean id="mysessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingResources">
<list>
<value>Login_Detailshbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="checkWriteOperation" >false</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="mysessionFactory" />
</bean>
<bean id="d" class="com.uday.Login_DetailsDao">
<constructor-arg ref="mysessionFactory" />
</bean>
</beans>
DAO Class:
package com.uday;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
public class Login_DetailsDao {
private final SessionFactory sessionFactory;
public Login_DetailsDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Transactional
public void saveEmployee(Login_Details e){
sessionFactory.getCurrentSession().save(e);
}
public boolean isLogoinSuccessfull(String uName , String password) {
List<Login_Details> a= getEmployees();
Iterator<Login_Details> i = a.iterator();
while(i.hasNext()) {
Login_Details ld = i.next();
String mobileNo = ld.getMobileNo();
String pas = ld.getPassword();
if(mobileNo != null && mobileNo.equals(uName) && pas != null && pas.equals(password)) {
return true;
}
}
return false;
}
#Transactional
public List<Login_Details> getEmployees(){
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Login_Details.class);
List<Login_Details> l = criteria.list();
return l;
}
}
Controller Class:
package com.uday;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
public class ControllerSignUp_Login {
#Autowired
private final Login_DetailsDao dao;
#Autowired
public ControllerSignUp_Login(Login_DetailsDao login_DetailsDao) {
this.dao = login_DetailsDao;
}
#RequestMapping("/hello")
#Transactional
public String diaplay(#RequestParam("name") String name, #RequestParam("pass") String pass,Model m) {
if(dao.isLogoinSuccessfull(name , pass)) {
m.addAttribute("message", "Hello"+name);
return "Success";
}
else {
m.addAttribute("message", "You have Entered Wrong pin");
return "Failure";
}
}
#RequestMapping("/SignUp")
public String redirect() {
System.out.println("ControllerSignUp_Login.display()");
return "signup";
}
#RequestMapping("/login")
public String display() {
System.out.println("ControllerSignUp_Login.display()");
return "login";
}
#RequestMapping("/updateDetails")
#Transactional
public String display(HttpServletRequest req , Model M) {
String firstName=req.getParameter("firstName");
String lastName=req.getParameter("lastName");
String mobileNo=req.getParameter("mobileNo");
String address=req.getParameter("address");
String city=req.getParameter("city");
String password=req.getParameter("password");
if(checkLength(firstName) && checkLength(lastName) && checkLength(mobileNo) && checkLength(address) && checkLength(city) && checkLength(password)) {
Login_Details ld = new Login_Details();
ld.setFirstName(firstName);
ld.setLastName(lastName);
ld.setCity(city);
ld.setAddress(address);
ld.setMobileNo(mobileNo);
ld.setPassword(password);
dao.saveEmployee(ld);
M.addAttribute("message", "SignUp Successfull !! Thank You");
M.addAttribute("displayLogin", true);
return "Success";
}
else {
M.addAttribute("message","SignUp Failed !! All details are mandatory.");
return "signup";
}
}
public boolean checkLength(String s) {
if(s != null && s.length() > 0) {
return true;
}
return false;
}
}
Project Structure looks like below
Instead of getting current session and making the transaction opened new session that's it worked like charm!!!
I don't know why it is not working if I am getting current session!!
#Transactional
public void saveEmployee(Login_Details e){
System.out.println("Login_DetailsDao.saveEmployee()"+e.getMobileNo());
SessionFactory sf = hbt.getSessionFactory();
//Changed here
Session session =sf.openSession(); //Session session =sf.getCurrentSession();
Transaction t =session.beginTransaction();
session.persist(e);
t.commit();
session.close();
}

Write operations are not allowed with spring and hibernate

when I try to save an object I get write operations are not allowed.
Here is the code.
configuration for transaction manager
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate" >
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven />
Service Class
#Service
public class MemberDetailServiceImpl implements MemberDetailService {
#Autowired
private MemberDetailsDao memberDetailsDao;
#Transactional(readOnly = false)
public String saveExtraInfoMember(MemberActivity activity){
return memberDetailsDao.saveExtraInfoMember(activity);
}
Dao
#Repository
public class MemberDetailsDaoImpl implements MemberDetailsDao {
#Autowired
HibernateTemplate hibernateTemplate;
public String saveExtraInfoMember(MemberActivity activity) {
// TODO Auto-generated method stub
String result=null;
hibernateTemplate.saveOrUpdate(activity);
return "";
}

CustomDateEditor not working in Spring 4.1.6

I am using a Date dob; field in my pojo class in spring 4.1.6 using maven
below are the files associated with my app.
// this is my pojo class.
package com.aamir;
import java.util.Date;
public class Student {
private String firstName;
private Date dob;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
}
// this is my client class
package com.aamir;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ClientStud1 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("s1");
System.out.println(student.getFirstName());
System.out.println(student.getDob());
}
}
// and finally this is my beans.xml 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"
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/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="s1" class="com.aamir.Student">
<property name="firstName" value="aamir"/>
<property name="dob" value="12-12-1996"/>
</bean>
<bean id="dateEditor"
class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="dd-MM-yyyy"/>
</bean>
</constructor-arg>
<constructor-arg value="true"/>
</bean>
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value-ref="dateEditor"/>
</map>
</property>
</bean>
</beans>
and I get this exception every time I try to run the client
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.beans.factory.config.CustomEditorConfigurer#0' defined in class path resource [beans.xml]:
Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.util.LinkedHashMap' to required type 'java.util.Map' for property 'customEditors'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [org.springframework.beans.propertyeditors.CustomDateEditor] to required type [java.lang.Class] for property 'customEditors[java.util.Date]': PropertyEditor [org.springframework.beans.propertyeditors.ClassEditor] returned inappropriate value of type [org.springframework.beans.propertyeditors.CustomDateEditor]
Note that PropertyEditor are stateful, so you should not register instances directly.
Register property editor classes via customEditor property
Add PropertyEditorRegistrars via propertyEditorRegistrars property in CustomEditorConfigurer
As you want to configure the property editor instance, use property editor registrar instead.
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="org.example.CustomDateEditorRegistrar"/>
</list>
</property>
</bean>
As per the official documentation , the recommended way of registering a PropertyEditor is to create a class that implements propertyEditorRegistrar interface. Each propertyEditorRegistrar can register any number of propertyEditors on a given registry.
Two such implementaions are descibed below:
Approach 1: create a generalized class that implements PropertyEditorRegistrar.
This class can be used for any propertyEditor(s), so you can keep this class in your utils.
Lets name it CustomEditorRegistrar and it looks like this:
public class CustomEditorRegistrar implements PropertyEditorRegistrar
{
Class<?> t;
PropertyEditor propertyEditor;
public CustomEditorRegistrar(Class<?> t, PropertyEditor propertyEditor)
{
this.t = t;
this.propertyEditor = propertyEditor;
}
#Override
public void registerCustomEditors(PropertyEditorRegistry registry)
{
registry.registerCustomEditor(t, propertyEditor);
}
}
. The bean definition to register a CustomDateEditor is as below:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="mky.spring.property.editor.date.CustomEditorRegistrar">
<constructor-arg index="0">
<value type="java.lang.Class">java.util.Date</value>
</constructor-arg>
<constructor-arg index="1">
<bean class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg index="0">
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="dd-MM-yyyy" />
</bean>
</constructor-arg>
<constructor-arg index="1" value="true" />
</bean>
</constructor-arg>
</bean>
</list>
</property>
</bean>
<bean
name="Customer"
class="mky.spring.property.editor.date.Customer"
p:name="Customer 1"
p:address="CounterHills LA"
p:deliveryDate="12-11-2016"
p:issueDate="12-10-2016" />
Sys-out client:
public class TestGenericClient
{
ApplicationContext ctx;
public TestGenericClient()
{
ctx = new ClassPathXmlApplicationContext("genericPropertyEditorRegistrar-beans.xml");
}
public static void main(String[] args)
{
System.out.println(new TestGenericClient().ctx.getBean("Customer"));
}
}
And the output is this:
Name=Customer 1
Address=CounterHills LA
Issue Date=Wed Oct 12 00:00:00 GST 2016
deliveryDate=Sat Nov 12 00:00:00 GST 2016
Approach2: create a specific propertyEditorRegistrar eg, for Date
public class CustomDateEditorRegistrar implements PropertyEditorRegistrar
{
#Override
public void registerCustomEditors(PropertyEditorRegistry registry)
{
registry.registerCustomEditor(java.util.Date.class, new CustomDateEditor(new SimpleDateFormat("dd-MM-yyyyy"),true));
}
}
And the bean declaration for this specific CustomDateEditor is :
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="mky.spring.property.editor.date.CustomDateEditorRegistrar" />
</list>
</property>
</bean>
Sys-out cleint:
public TestDateClient()
{
ctx = new ClassPathXmlApplicationContext("datePropertyEditorRegistrar-beans.xml");
}
public static void main(String[] args)
{
System.out.println(new TestDateClient().ctx.getBean("Customer"));
}
And the same output :
Name=Customer 1
Address=CounterHills LA
Issue Date=Wed Oct 12 00:00:00 GST 2016
deliveryDate=Sat Nov 12 00:00:00 GST 2016

Transaction support for Discriminator model in Muiti-tenancy with Spring + Hibernate

Our current development based on Discriminator model in Multi-tenancy. Following is the technical stack we are currently engage with,
Spring 3.1.1.RELEASE
Hibernate 4.1.6.Final
We are maintain tenant id by keep one column separately in each table. Tenant id filter when session is created.
Example model class.
#Entity
#FilterDef(name = "tenantFilter", parameters = #ParamDef(name = "tenantIdParam", type = "string"))
#Filters(#Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
#Table(name = "assessment")
public class Assessment implements java.io.Serializable, Comparable<Assessment> {
private static final long serialVersionUID = -2231966582754667029L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#Column(name = "tenant_id", nullable = false, updatable = false)
private String tenantId;
// rest of the code...
}
This is the configuration of session factory
<!-- create database connection pool -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="jdbc:mysql://${jdbc.host}:3306/${jdbc.database}?createDatabaseIfNotExist=true&autoReconnect=true&useUnicode=true&connectionCollation=utf8_general_ci&characterEncoding=UTF-8" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="idleConnectionTestPeriodInMinutes" value="60"/>
<property name="idleMaxAgeInMinutes" value="240"/>
<property name="maxConnectionsPerPartition" value="30"/>
<property name="minConnectionsPerPartition" value="10"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="5"/>
<property name="statementsCacheSize" value="100"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="lk.gov.elg.orm.model"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.hbm2ddl.auto=update
</value>
</property>
</bean>
<bean id="tenantBasedSessionFactory" class="lk.gov.elg.orm.dao.impl.TenantBasedSessionFactoryImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Tenant base session factory
public class TenantBasedSessionFactoryImpl implements TenantBasedSessionFactory {
private SessionFactory sessionFactory;
#Override
public Session getTenantBasedSession(Object tenantId) {
Session session = sessionFactory.openSession();
session.enableFilter("tenantFilter").setParameter("tenantIdParam", tenantId);
return session;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getAllTenantBasedSession() {
Session session = sessionFactory.openSession();
return session;
}
}
sample Service class
#Service("assessmentService")
public class AssessmentServiceImpl implements AssessmentService {
#Autowired
private AssessmentDao assessmentDao;
public Long saveAssessment(Assessment assessment, Object tenantId) {
return assessmentDao.saveAssessment(assessment, tenantId);
}
}
Sample DAO class
#Repository("assessmentDao")
public class AssessmentDaoImpl implements AssessmentDao {
#Autowired
private TenantBasedSessionFactory tenantBasedSessionFactory;
public Long saveAssessment(Assessment assessment, Object tenantId) {
Session session = tenantBasedSessionFactory.getTenantBasedSession(tenantId);
try {
session.beginTransaction();
session.save(assessment);
session.getTransaction().commit();
return assessment.getId();
} catch (HibernateException e) {
logger.error("Error in persist assessment:", e);
session.getTransaction().rollback();
return null;
} finally {
session.close();
}
}
}
I would like to know is there a way to get the spring transaction support with this Discriminator model for database transactions ?
And the other thing is I would like to know is there any advantage of give transaction handling to spring rather than handling it by our side?
Thanks in advance.
i had similar problem and i have resolved it using aspect instead of customizing sessionfactory, so i can leverage annotation driven transaction support
Below code is for aspect which works on annotation #Tennant
#Aspect
public class TennantAspect {
#Autowired
private SessionFactory sessionFactory;
#Around("#annotation(Tennant)")
public Object enableClientFilter(ProceedingJoinPoint pjp) throws Throwable {
Object obj;
boolean isDAO=(pjp.getTarget() instanceof BaseDAO<?,?>);
try {
if(isDAO){
Authentication auth=SecurityContextHolder.getContext().getAuthentication();
if(auth!=null){
User user=(User) auth.getPrincipal();
this.sessionFactory.getCurrentSession().enableFilter("clientFilter").setParameter("clientId", user.getClientId());
}
}
obj=pjp.proceed();
}finally {
if(isDAO)
this.sessionFactory.getCurrentSession().disableFilter("clientFilter");
}
return obj;
}
}
Hope this solves your problem.
Alternatively you can also look at tenancy support by hiberante & spring
http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch16.html
https://github.com/mariofts/spring-multitenancy

"No Session found for current thread" when adding #Autowire

I've seen several similar questions, but none of the suggested solutions helped me.
Summary: when I create and inject the beans on the .xml, it works; but when I use #Autowire or #Resource, it doesn't.
Environment: Spring3, Hibernate4, Tomcat7.
Details: the following setup DOES work:
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml
/WEB-INF/spring/users-context.xml
</param-value>
</context-param>
root-context.xml:
<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/venus" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.airbus.genesis.marte.dal" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
users-context.xml:
<bean id="usersDAO" class="com.airbus.genesis.marte.dal.users.UsersDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
BL object:
#Service("usersManager")
#Transactional(readOnly = true)
public class UsersManager implements IUsersManager {
#Autowired
#Qualifier("usersDAO")
private IUsersDAO usersDAO;
#Override
public List<User> getUsers() {
return usersDAO.getUsers();
}
}
DAO object (notice that #Repository and #Resource are commented):
//#Repository("usersDAO")
#Transactional(readOnly = true)
public class UsersDAO implements IUsersDAO {
// #Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
#Override
public List<User> getUsers() {
#SuppressWarnings("unchecked")
List<User> res = (List<User>) getSessionFactory().getCurrentSession()
.createQuery("from User").list();
return res;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
But the following one DOES NOT work:
users-context.xml:
<!--
<bean id="usersDAO" class="com.airbus.genesis.marte.dal.users.UsersDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
-->
DAO object (notice that #Repository and #Resource are uncommented now):
#Repository("usersDAO")
#Transactional(readOnly = true)
public class UsersDAO implements IUsersDAO {
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
#Override
public List<User> getUsers() {
#SuppressWarnings("unchecked")
List<User> res = (List<User>) getSessionFactory().getCurrentSession()
.createQuery("from User").list();
return res;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
org.hibernate.HibernateException: No Session found for current thread is raised:
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
com.airbus.genesis.marte.dal.users.UsersDAO.getUsers(UsersDAO.java:23)
com.airbus.genesis.marte.bl.users.UsersManager.getUsers(UsersManager.java:22)
[...]
The same happens if I use #Autowire instead of #Resource.
I guess it is some kind of misunderstanding on my side, but cannot find where. Any idea?
The problem is likely that #Repository and #Service annotations are being picked up in the dispatcher-servlet.xml configuration (do you use context:component-scan?), so these beans are created in the dispatcher servlet context instead of the root web app context.
A good practice is to put your service layer objects to the dedicated packages and use the specific package name as <context:component-scan/> base-package qualifier (like 'com.myproject.services'). You can also use filter expressions to include and exclude elements see examples here : #Service are constructed twice
and 4.10.3 section of the Spring documentation
See also Difference between applicationContext.xml and spring-servlet.xml in Spring Framework

Resources