I have a problem when annotating with @transactional a method of my service class. Such annotation cause a NoSuchBeanDefinitionExcpetion in my test class where the service class is autowired. If the transactional annotation is removed it works fine again. Why is this happening, I couldn't find a clue in spring documentation.
This is my 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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="<mypackage...>" />
<import resource="data-context.xml"/>
<import resource="resources-context.xml"/>
<import resource="persistence-context.xml"/>
This is part of my persistence-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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourceConnection" />
<property name="configLocation"
value="classpath:configuration/mybatis/config.xml"></property>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceConnection" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="accessDao" class="dao.impl.AccessDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="utilitiesDao" class="dao.impl.UtilitiesDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="portafoglioDao" class="dao.impl.PortafoglioDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
part of my test class
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:configuration/applicationContext.xml" })
public class MyTest {
@Autowired
ApplicationContext context;
@Autowired
DriverManagerDataSource dataSourceConnection;
@Autowired
AccessAppDelegate accessApp;
the class that generates the problem
@Service
public class AccessAppDelegate extends Delegate implements DelegateInterface {
private PersonalCodesManager pcm;
AccessApp accessReq;
@Override
@Transactional
public void elaborateRequestImpl() throws Exception {
accessReq = (AccessApp) requestBean;
if (accessReq.getLan() != null) {
lang = StringUtilities.toLan(accessReq.getLan());
accessDao.updateDeviceLanguage(accessReq.getUser().getImei(),
accessReq.getLan());
}
if (requestWrap.getRequestType().compareTo(
ApplicativeConsts.INTESTAZIONE_REQUEST_LOGIN) == 0)
elaborateRequestLogin();
else
elaborateRequestAttivazione();
}
some private methods...
public PersonalCodesManager getPcm() {
return pcm;
}
public void setPcm(PersonalCodesManager pcm) {
this.pcm = pcm;
}
@Override
public String getUserId() {
accessReq = (AccessApp) requestBean;
return accessReq.getUser().getId();
}
@Override
public Class getRequestType() {
return AccessApp.class;
}
}
the class Delegate
@Component
public class Delegate{
String jsonReq;
String jsonRes;
@Autowired
ApplicationContext ctx;
@Autowired
AccessDao accessDao;
Locale lang;
java.sql.Timestamp timestamp;
RequestWrapper requestWrap;
UserAndDeviceTable userInfo;
AuthUserTable auth;
BaseResponse responseBean;
BaseRequest requestBean;
public void elaborateRequest(String body,boolean authenticationRequired){
DelegateInterface endpointImplementation = (DelegateInterface) this;
timestamp = new java.sql.Timestamp(new java.util.Date().getTime());
if (body.startsWith("json=")){
body = body.split("json=")[1];
}
requestWrap = new RequestWrapper(body);
requestBean=requestWrap.getReq(endpointImplementation.getRequestType());
this.jsonReq = requestWrap.getRequestBody();
lang = StringUtilities.toLan("en");
try {
if (authenticationRequired) {
auth = this.accessDao.checkSessioneAperta(requestBean.getSessionID(), timestamp);
if(auth==null) {
throw new Exception("Unauthorized Access");
}else{
setUserInfo(auth.getEmail());
}
}else{
setUserInfo(endpointImplementation.getUserId());
}
if(userInfo!=null){
lang=StringUtilities.toLan(userInfo.getLanguage());
}
endpointImplementation.elaborateRequestImpl();
} catch (Exception e) {
responseBean= new BaseResponse(String.valueOf(ApplicativeConsts.RC_ERRORE),ctx.getMessage(ApplicativeConsts.MSG_ERRORE_GENERAL, null, lang));
e.printStackTrace();
}
try {
ObjectMapper mapper = new ObjectMapper();
this.jsonRes = mapper.writeValueAsString(responseBean);
} catch (Exception e) {
e.printStackTrace();
}
}
public ModelMap getResponse(ModelMap model) {
// TODO Auto-generated method stub
model.addAttribute(ApplicativeConsts.INTESTAZIONE_RESPONSE, responseBean);
return model;
}
public void setUserInfo(String email) {
List<UserAndDeviceTable> userList = accessDao.findUserAndDeviceTableByEmail(email);
if (userList.size()==1){
this.userInfo = userList.get(0);
}
}
public String getJsonReq() {
return jsonReq;
}
public String getJsonRes() {
return jsonRes;
}
public BaseResponse getResponseBean() {
return responseBean;
}
}
the interface
public interface DelegateInterface {
public void elaborateRequestImpl() throws Exception;
public ModelMap getResponse(ModelMap response);
public String getUserId();
public Class getRequestType();
}
The exception
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'TestClass': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: it.something.be.delegates.AccessAppDelegate it.something.controller.somethingControllerTestAuto.accessApp; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [it.something.be.delegates.AccessAppDelegate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:220)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:301)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:303)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: it.something.be.delegates.AccessAppDelegate it.something.controller.somethingControllerTestAuto.accessApp; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [it.something.be.delegates.AccessAppDelegate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:506)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
... 26 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [it.something.be.delegates.AccessAppDelegate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:924)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:793)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 28 more
This is because you are requesting spring to auto wire to a field which is not an interface. Adding @Transactional results in your object being wrapped in a proxy - the proxy will implement all the interfaces implemented by the class. It can be auto wired to fields of the interface type only. Change the below field definition in your test to the corresponding interface to fix the issue.
@Autowired
AccessAppDelegate accessApp;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With