It's been about 5 hours trying to update an object through hibernate in my application using Spring MVC 3 and OpenSessionInViewFilter without any luck.
I've possibly gone through all the threads available in StackOverflow and other forums!
Hibernate doesn't throw any error, and says the object was updated but it doesn't reflect in my DB.
Any help would be massively appreciated.
So, here's my JSON request to update:
{
"id": "14",
"name": "Whatever",
"contactNumber": "918026754027",
"manager": "Vishwas", --> I've updated this value
"capacity": "222",
"addressId": "31",
"streetAddress": "1168, 1st Block, 17th Main, ABC",
"countryId": "1",
"stateId": "1",
"cityId": "1",
"area": "DEF",
"pincode": "560050"
}
Controller:
@RequestMapping(value = "/branches/update", method = RequestMethod.POST, headers = {"Content-Type=application/json"})
@ResponseBody
public Map<String, Object> updateBranch(@RequestBody Map<String, String> requestMap) {
boolean status = false;
boolean branchStatus = false;
Map<String, Object> statusMap = new HashMap<String, Object>();
Branch branch = new Branch();
Address address = new Address();
address.setId(Long.parseLong(requestMap.get("addressId")));
address.setCountry(countryService.getCountryById(Long.parseLong(requestMap.get("countryId"))));
address.setState(stateService.getStateById(Long.parseLong(requestMap.get("stateId"))));
address.setCity(cityService.getCityById(Long.parseLong(requestMap.get("cityId"))));
address.setType("BRANCH");
address.setArea(requestMap.get("area"));
address.setStreetAddress(requestMap.get("streetAddress"));
address.setPincode(requestMap.get("pincode"));
address.setModifiedBy("vishwas");
address.setModifiedTimestamp(new Date());
status = addressService.updateAddress(address);
if (status) {
branch.setId(Long.parseLong(requestMap.get("id")));
branch.setName(requestMap.get("name"));
branch.setAddress(address);
branch.setContactNumber(requestMap.get("contactNumber"));
branch.setManager(requestMap.get("manager"));
branch.setActive(true);
branch.setCapacity(Integer.parseInt(requestMap.get("capacity")));
branch.setModifiedTimestamp(new Date());
branch.setModifiedBy("vishwas");
branchStatus = branchService.updateBranch(branch);
}
if (branchStatus) {
statusMap.put("status", branchStatus);
statusMap.put("message", "Branch was updated successfully");
} else {
boolean delStatus = addressService.deleteAddress(address);
statusMap.put("status", branchStatus);
statusMap.put("message", "Problem updating branch. Please check with your system administrator");
}
return statusMap;
}
Service class:
@Service("branchService")
@Transactional
public class BranchServiceImpl implements BranchService {
@Autowired
private BranchDAO branchDAO;
private static Logger logger = Logger.getLogger(BranchService.class.getName());
public boolean updateBranch(Branch branch) {
logger.debug("Processing request to dao to update a branch --> " + branch.getId());
return branchDAO.updateBranch(branch);
}
}
DAO method:
public boolean updateBranch(Branch branch) {
boolean status = false;
try {
logger.debug("Trying to update a branch --> " + branch.getId());
sessionFactory.getCurrentSession().update(branch);
status = true;
} catch (HibernateException exception) {
logger.error("Problem updating a branch --> " + exception.getMessage());
} catch (Exception exception) {
logger.error("Problem updating a branch --> " + exception.getMessage());
}
return status;
}
**Update 2: As suggested by Mr.Deinum, I've moved transaction manager config to o2-data.xml and now scanning only the controllers in the dispatcher while scanning other components in o2-data.xml
Data Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns="http://www.springframework.org/schema/beans"
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.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
">
<context:component-scan base-package="com.adwitiya.o2plus">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driverClass}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<!-- Hibernate Session Factory -->
<bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan">
<array>
<value>com.adwitiya.o2plus.model</value>
</array>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
</value>
</property>
</bean>
<!-- Hibernate Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<!-- Activates annotation based transaction management -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Dispatcher Configuration:
<?xml version="1.0" encoding="UTF-8"?>
<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="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<context:component-scan base-package="com.adwitiya.o2plus">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven>
<mvc:message-converters>
<!-- Use the HibernateAware mapper instead of the default -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.adwitiya.o2plus.utilities.HibernateAwareObjectMapper"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:resources mapping="/gui/**" location="/gui/"/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>O2 Plus</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/o2-data.xml
/WEB-INF/spring/o2-utils.xml
/WEB-INF/spring/o2-security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>mySessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>o2-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/o2-dispatcher-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>o2-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
<context:component-scan base-package="com.adwitiya.o2plus" />
This <context:component-scan ... />
is located the configuration that is loaded by the DispatcherServlet
.
<tx:annotation-driven transaction-manager="transactionManager"/>
The <tx:annotation-driven />
is located in the configuration that is loaded by the ContextLoaderLIstener
.
A Bean(Factory)PostProcessor
only operates on beans in the same ApplicationContext
that it is loaded in. It doesn't do anything for beans in parent or child contexts. The <tx:annotation-driven />
registers an interceptor (or aspect) which is processed by an InfrastructureAdvisorAutoProxyCreator
which is a BeanPostProcessor
.
Either move your <tx:annotation-driven />
to your configuration of the DispatcherServlet
or modify your component scan. The ContextLoaderListener
should scan for anything but @Controller
annotated beans, whereas the DispatcherServlet
should scan only for @Controller
annotated beans.
ContextLoaderListener
configuration.
<context:component-scan base-package="com.adwitiya.o2plus">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
DispatcherServlet
configuration
<context:component-scan base-package="com.adwitiya.o2plus" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>