Overriding transactional Annotation Spring + hibernate - java

I have this DAO:
#Transactional("transactionManager")
public class DAO{
public void save(String a){...}
}
I have this class:
public class test{
...
#Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void save(){
DAO.save("a");
DAO.save("b");
}
}
I want the "save" method to rollback when it throws an exception, but it doesn't seem to work when an exception occurs it does not rollback, what is the proper approach for this? All the other methods in the DAO are transactional. Is there a way I can override the transactional settings of the override?
EDIT:
I have updated to be, and it is still not working when throwing exception:
public class test{
...
public void save(){
Service.test(a,b);
}
}
public class Service{
#Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void testSave(object a, object b){
dao.updateEntry(a);
dao.updateEntry(b);
}
}

Remove the Transactional annotation from the Dao layer and place a Transactional annotation in your service layer. Take a look at my code:-
#Transactional
#Service
public class Service {
#Autowired
private Dao1 dao1;
#Autowired
private Dao2 dao2;
public Dao1 getDao1() {
return dao1;
}
public void setDao1(Dao1 dao1) {
this.dao1 = dao1;
}
public Dao2 getDao2() {
return dao2;
}
public void setDao2(Dao2 dao2) {
this.dao2 = dao2;
}
public void insertData(){
dao1.insert1();
dao2.insert2();
}
In above code, if dao2.insert2() fails then dao1.insert1() will rollback.
In case when you have multiple methods in service class with different transaction properties :
You can define the #Transactional annotation on your public methods with below rule:-
When using proxies, you should apply the #Transactional annotation
only to methods with public visibility. If you do annotate protected,
private or package-visible methods with the #Transactional annotation,
no error is raised, but the annotated method does not exhibit the
configured transactional settings.
Link1: Transactional annotation on whole class + excluding a single method
Transaction support configuration setup:-
1) spring-config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.concept" />
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
</beans>

Related

NPE while accessing through #Autowired [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
I have the below code in my SpringBoot project which is throwing NPE at a specific line mentioned.
Exception in thread "main" java.lang.NullPointerException
at com.temp.controller.Controller.triggerJob(Controller.java:15)
at com.temp.Application.main(Application.java:19)
Application.java
#Configuration
#SpringBootApplication
#ImportResource({"classpath:applicationContext.xml"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
Controller controller = new Controller();
controller.triggerJob();
}
}
Controller.java
#Controller
public class Controller {
#Autowired
private Service Service;
public void triggerJob() {
Service.selectRecords();
}
}
Service.selectRecords(); is where the NPE is being thrown
Service.java
public interface Service {
List<VO> selectRecords();
}
ServiceImpl.java
#Service
public class ServiceImpl implements Service {
#Autowired
private Dao dao;
#Override
public List<VO> selectRecords() {
return dao.selectRecords();
}
}
applicationContext.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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<util:properties id="configProperties"
location="file:${app.config.home}/config/config-${spring.profiles.active}.properties" />
<context:property-placeholder
location="file:${app.config.home}/config/config-${spring.profiles.active}.properties" />
<bean id="crypt" class="com.temp.util.MyUtil">
<property name="userId" value="${username}"></property>
<property name="password" value="${password}"></property>
<property name="key" value="123456789012345678901234"></property>
</bean>
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${connection}" />
<property name="username" value="#{crypt.userId}" />
<property name="password" value="#{crypt.password}" />
</bean>
<bean id="namedJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="datasource" />
</bean>
</beans>
I have a similar project like this and have compared the configuration of both and they are the same except for 2 things.
The spring boot starter version is 2.4.2 for this project and 1.5.3 for the other project.
Java version is 11 for this project and 1.8 for the other project.
Not sure where I'm going wrong.
Am I missing something? Kindly help.
You are creating new instance
Controller controller = new Controller();
manually and this instance is not in Spring context. Therefore, the injected (autowired) instance of Service is null. #Autowired only works when the instance exists in Spring context.
The best approach is to keep Controller testable is injection via constructor:
#Configuration
#SpringBootApplication
#ImportResource({"classpath:applicationContext.xml"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
Controller controller = new Controller(new ServiceImpl(new DaoImpl()));
controller.triggerJob();
}
}
Inject the instance via constructor:
#Controller
public class Controller {
private final Service Service;
public Controller(final Service Service) {
this.service = service;
}
public void triggerJob() {
Service.selectRecords();
}
}
And also inject the Dao dependency via constructor:
#Service
public class ServiceImpl implements Service {
private final Dao dao;
public ServiceImpl(final Dao dao) {
this.dao = dao;
}
#Override
public List<VO> selectRecords() {
return dao.selectRecords();
}
}
For Spring version above 4.3, #Autowired could be omitted from top of the constructor, Spring scans the injection automatically and injects the dependency via constructor.
For Spring version below 4.3, add #Autowired on top of constructors i.e.:
#Controller
public class Controller {
private final Service Service;
#Autowired
public Controller(final Service Service) {
this.service = service;
}
public void triggerJob() {
Service.selectRecords();
}
}

Field in Aspect injected after its first use, causing NullPointerException at startup

ABSTRACT:
I have some initialisation operations executed in #PostConstruct of #Service ServiceInitialiserFacsimile. Those operations include a call to a method after whose execution an Aspect (DoAttionalStuffAspect) is applied.
The Aspect is instantied through aspectOf, so it is handled by the Spring Container, but unfortunately its dependencies are injected AFTER the execution of ServiceInitialiserFacsimile #PostConstruct, resulting in a NullPointerException.
How can I tell the Spring Container to inject first the fields in the Aspect and then instantiate the ServiceInitialiserFacsimile ?
I tried with an Autowired constructor for the aspect, but I think in the end AspectJ requires the no-arg constructor, so it was no help
CODE
This is a Sample I created in order to reproduce the issue I have in a much more complicated app. Here is the project if you want to check it out. https://github.com/alessiop86/spring3-mvc-maven-xml-hello-world
Code below:
This is the initialisation class:
#Component
public class ServiceInitialiserFacsimile {
private final SampleService sampleService;
#Autowired
public ServiceInitialiserFacsimile(SampleService ss) {
this.sampleService = ss;
}
#PostConstruct
public void initialiseAllTheServices() {
this.sampleService.init();
}
}
This is the service with some custom logic that requires to be initialised by the ServiceInitialiserFacsimile #PostConstruct:
#Service
public class SampleService {
public void init() {
System.out.println("do some stuff");
try {
execute();
}
catch(Exception e) {
System.err.println("I do not want to block to whole framework initialisation");
}
}
#DoAdditionalStuff
public void execute() {
System.out.println("Phase 1");
}
}
This is the annotation I use in the aspect definition
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface DoAdditionalStuff {
}
This is the aspect
#Aspect
public class AdditionalStuffAspect {
private AdditionalStuffService service;
public AdditionalStuffService getService() {
return service;
}
public void setService(AdditionalStuffService service) {
this.service = service;
}
#Pointcut(value="execution(public * *(..))")
private void anyPublicMethod() { }
#AfterReturning("anyPublicMethod() && #annotation(doAdditionalStuff)")
public void afterReturning(JoinPoint jointPoint, DoAdditionalStuff doAdditionalStuff) {
System.out.println(jointPoint);
service.doStuff();
}
}
This is the service that is created, but not yet instantiated when the aspect is run:
#Service
public class AdditionalStuffService {
public void doStuff() {
System.out.println("Phase2: additional stuff");
}
}
Spring context xml configuration file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="initialisation.mess"/>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/"/>
<mvc:annotation-driven/>
<bean class="initialisation.mess.aspects.AdditionalStuffAspect" factory-method="aspectOf">
<property name="service" ref="additionalStuffService" />
</bean>
</beans>
I was able to enforce a dependency on the ServiceInitialiserFacsimile from the Aspect by setting an id in the xml:
<bean id="myAspect" class="initialisation.mess.aspects.AdditionalStuffAspect" factory-method="aspectOf">
<property name="service" ref="additionalStuffService" />
</bean>
and then specifying the dependency of ServiceInitialiserFacsimile from the spring managed AdditionalStuffAspect with a #DependsOn annotation:
#Component
#DependsOn("myAspect")
public class ServiceInitialiserFacsimile {
private final SampleService sampleService;
#Autowired
public ServiceInitialiserFacsimile(SampleService ss) {
this.sampleService = ss;
}
#PostConstruct
public void initialiseAllTheServices() {
this.sampleService.init();
}
}

How to use #Required annotation in setter injection in spring?

#required annotation usage. I tried giving this above setter method and tried to find the bean from context without setting this dependency. I got the object with the dependency is set null, my expectation was spring will throw some exception. Please guide me where I am doing wrong?
#Required to make it mandatory that the dependency has to be injected
Let us example:
We need to use RequiredAnnotationPostProcessor which checks whether #Required dependencies have been injected or not
public class BankService {
private CustomerService customerService;
private BillPaymentService billPaymentService;
#Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
#Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}
}
The configuration is like
<bean id="custService" class="xml.CustomerServiceImpl" />
<bean id="billingService" class="xml.BillPaymentServiceImpl" />
<bean id="bankService" class="xml.BankServiceImpl">
<property name="customerService" ref="custService" />
<property name="billPaymentService" ref="billingService" />
</bean>
<bean class=”o.s.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
If we don’t set both the properties we will get an error for the BankService configuration as both are #Required.
I hope this helps!!
Same anwer by bmt - just adding here what i did to verify.
package com.requiredAnnotation;
import org.springframework.beans.factory.annotation.Required;
public class BankService {
private CustomerService customerService;
private BillPaymentService billPaymentService;
#Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
#Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}
public BillPaymentService getBillPaymentService() {
return billPaymentService;
}
public CustomerService getCustomerService() {
return customerService;
}
}
package com.requiredAnnotation;
public class CustomerService {
}
package com.requiredAnnotation;
public class BillPaymentService {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="customerService" class="com.requiredAnnotation.CustomerService" />
<bean id="billPaymentService" class="com.requiredAnnotation.BillPaymentService" />
<bean id="bankService" class="com.requiredAnnotation.BankService">
<property name="customerService" ref="customerService" />
<!-- <property name="billPaymentService" ref="billPaymentService" /> -->
</bean>
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
</beans>
package com.requiredAnnotation;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:com/requiredAnnotation/beans-required.xml");
BankService bankService = applicationContext.getBean(BankService.class);
System.out.println("bankService got.");
System.out.println("getCustomerService - " + bankService.getCustomerService());
System.out.println("getBillPaymentService - " + bankService.getBillPaymentService());
}
}

Testing steps of DAO layer and Service layer of Spring MVC and Hibernate using Junit

Pardon me if it is a stupid question.I'm trying to learn Spring MVC,Hibernate,Junit by doing a project. I'm using MySQL database. Problem is I'm not understanding how to test DAO layer or Service layer of my project Junit.I've tested my model classes easily. I searched for DAO & Service layers, but the tutorials I saw,made me more confused. None of them actually match pattern of my project. I know in-memory used for testing process. Some testing configuration is also needed. Somewhere text-context,somewhere used java configuration class. Now, I actually want to know what steps I really have to do one by one to test this layers and it will be helpful if you can tell me what have to be done in each step. I've several DAO,Service,and Model classes. I've given one class from each layer.
My servlet-context.xml file which is in WEB-INF:
<?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:beans="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-4.0.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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- Enable #Controller annotation support -->
<mvc:annotation-driven />
<!-- Map simple view name such as "test" into /WEB-INF/test.jsp -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- Scan classpath for annotations (eg: #Service, #Repository etc) -->
<context:component-scan base-package="com.mahin"/>
<!-- JDBC Data Source. It is assumed you have MySQL running on localhost port 3306 with
username root and blank password. Change below if it's not the case -->
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/webchatapp"/>
<property name="username" value="root"/>
<property name="password" value=""/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<!-- Hibernate Session Factory -->
<bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan">
<array>
<value>com.mahin.models</value>
</array>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
</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>
One of my model class
package com.mahin.models;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="friends")
public class Friends {
#Id #GeneratedValue
private long friendid;
private long reqsender;
private long reqreceiver;
private int rank;
private boolean granted;
public long getFriendid() {
return friendid;
}
public void setFriendid(long friendid) {
this.friendid = friendid;
}
public long getReqsender() {
return reqsender;
}
public void setReqsender(long reqsender) {
this.reqsender = reqsender;
}
public long getReqreceiver() {
return reqreceiver;
}
public void setReqreceiver(long reqreceiver) {
this.reqreceiver = reqreceiver;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public boolean getGranted() {
return granted;
}
public void setGranted(boolean granted) {
this.granted = granted;
}
}
One of my DAO class
package com.mahin.daos;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.mahin.models.Friends;
#Repository
public class FriendsDAOimpl implements FriendsDAO{
#Autowired
private SessionFactory sessionFactory;
private Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
#Override
public void addFriend(Friends friend) {
getCurrentSession().save(friend);
}
#Override
public void updateFriend(Friends friend) {
Friends friendToUpdate = getFriend(friend.getFriendid());
friendToUpdate.setGranted(friend.getGranted());
friendToUpdate.setRank(friend.getRank());
friendToUpdate.setReqreceiver(friend.getReqreceiver());
friendToUpdate.setReqsender(friend.getReqsender());
getCurrentSession().update(friendToUpdate);
}
#Override
public Friends getFriend(long friendid) {
Friends friend = (Friends) getCurrentSession().get(Friends.class, friendid);
return friend;
}
#Override
public void deleteFriend(long friendid) {
Friends friend = getFriend(friendid);
if (friend != null)
getCurrentSession().delete(friend);
}
#SuppressWarnings("unchecked")
#Override
public List<Friends> getFriends() {
return getCurrentSession().createQuery("from friends").list();
}
}
And finally one of my Service class
package com.mahin.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mahin.daos.FriendsDAO;
import com.mahin.models.Friends;
#Service
#Transactional
public class FriendsServiceimpl implements FriendsService{
#Autowired
private FriendsDAO friendsDAO;
#Override
public void addFriend(Friends friend) {
friendsDAO.addFriend(friend);
}
#Override
public void updateFriend(Friends friend) {
friendsDAO.updateFriend(friend);
}
#Override
public Friends getFriend(long friendid) {
return friendsDAO.getFriend(friendid);
}
#Override
public void deleteFriend(long friendid) {
friendsDAO.deleteFriend(friendid);
}
#Override
public List<Friends> getFriends() {
return friendsDAO.getFriends();
}
}
You have two options:
Unit Testing: Test if the method works as expected in isolation. This is the solely purpose of JUnit. For unit testing, you must not connect to external resources like a database. This is, you have to mock your data source provider and any other component that is external to the class you're testing. You can mock methods and classes using a mock framework like PowerMock, EasyMock or Mockito.
Integration Testing: Test if the method works as expected in an integrated environment. Here you test if the class can interact with other external resources like database connection, and perform its functionality integrated with these components.
For Spring projects, there is Spring Test framework which provides additional functionalities to JUnit test classes to do Unit or Integration Testing. Here's a basic example to perform integration test on your posted Dao class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("path/to/your/spring-config.xml")
public class MyTest {
#Autowired
FriendsDAO friendsDao;
#Test
public void testAddFriend() {
final int rank = 1;
Friends friend = new Friends();
friend.setRank(rank);
friendsDao.addFriend(friend);
final long friendId = friend.getId();
Friends insertedFriend = friendsDao.getFriend(friendId);
Assert.assertEquals(insertedFriend.getRank(), friend.getRank());
//assert if all necessary fields are equal
//or assert if both are equals in case your Friends class implements equals method
}
}

#Transactional annotation required due to 'org.hibernate.HibernateException: No Session found for current thread' exception

So, I read that the best place to put the #Transactional annotation was outside the DAO classes which contains the db access methods, like in a service class which use those methods.
Now, the problem is, once I've already remove this annotations from the DAO classes, I launch the DAO test methods and the aforementioned exception raised. I put back the annotations in the DAO classes and this exception doesn't raises anymore.
Then my question is: how can I clear my DAOs of this annotations and still have my tests working?
Let's add some code:
DAO class
public class UserDAO extends IDAO implements IUserDAO {
#Override
//#Transactional(readOnly=true)
public User get(int idUser) {
return (User) currentSession().get(User.class,idUser);
}}
IDAO Class
public abstract class IDAO {
protected SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session currentSession()
{
return sessionFactory.getCurrentSession();
}
}
Test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
public class UserDAOTest extends AbstractJUnit4SpringContextTests {
#Autowired
private IUserDAO userDAO;
#Test
public void testGetUser() throws Exception {
User user = userDAO.get(2);
assertNotNull(user);
}
}
app-config
<?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:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/waldb" />
<property name="username" value="user" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.wal.serverside.persistence.domain.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDAO" class="com.wal.serverside.persistence.DAO.UserDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="com.wal.serverside.persistence" />
</beans>
Gosh, how much stupid can I be?
My test class didn't extend from AbstractTransactionalJUnit4SpringContextTests, so there were nor transaction nor session inside my tests.
This fixed it all:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#Transactional
public class UserDAOTest extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private IUserDAO userDAO;
public void setUserDAO(IUserDAO userDAO) {
this.userDAO = userDAO;
}
#Test
public void testGetUser() throws Exception {
User user = userDAO.get(2);
assertNotNull(user);
}
}
Try to put not only #Transactional annotaition on your test class but also #TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false). Where you explicitly set the name of the transaction manager that you have defined in xml.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#Transactional(propagation=Propagation.REQUIRED, rollbackFor={Exception.class})
public class UserDAOTest {
...
}
Also transaction will not work if you explicitly create the application context in your test method and then get the bean from it:
ApplicationContext appContext = new ClassPathXmlApplicationContext(...);
SomeDAO someDAO = (SomeDAO) appContext.getBean(...);
instad of inhjecting it.
But I see this is not your case.

Categories