error autowiring service in test using spring 3 +j

2019-09-05 05:07发布

问题:

i have a problem with spring 3 tests using junit 4.10 and mybatis. I'm not able to autowire service in the test class.

Here the exception i get

Running it.infora.suap.service.MailReceiverAccountServiceTest
16:58:24,933  INFO TestContextManager:185 - @TestExecutionListeners is not present for class [class it.infora.suap.service.MailReceiverAccountServiceTest]: using defaults.
16:58:25,157  INFO XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [testApplicationContext.xml]
16:58:25,535  INFO GenericApplicationContext:500 - Refreshing org.springframework.context.support.GenericApplicationContext@17a6a4b: startup date [Mon Mar 04 16:58:25 CST 2013]; root of context hierarchy
16:58:25,740  INFO DefaultListableBeanFactory:581 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1a390f4: defining beans [mailReceiverAccountBean,mailReceiverAccountService,mailMessageService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,dataSource,sqlSessionFactory,sqlSession,org.mybatis.spring.mapper.MapperScannerConfigurer#0,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,mailMessageMapper,mailReceiverAccountMapper]; root of factory hierarchy
16:58:26,732 ERROR TestContextManager:324 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@823b18] to prepare test instance [it.infora.suap.service.MailReceiverAccountServiceTest@1f5c8d2]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'it.infora.suap.service.MailReceiverAccountServiceTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private it.infora.suap.service.MailReceiverAccountService it.infora.suap.service.MailReceiverAccountServiceTest.mailReceiverAccountService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [it.infora.suap.service.MailReceiverAccountService] 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:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private it.infora.suap.service.MailReceiverAccountService it.infora.suap.service.MailReceiverAccountServiceTest.mailReceiverAccountService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [it.infora.suap.service.MailReceiverAccountService] 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)
    ... 32 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [it.infora.suap.service.MailReceiverAccountService] 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:952)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:821)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
    ... 34 more

I tried to register manually the bean in the springBean file, but it get a null value.

my configurations and classes are

pom.xml

<properties>
        <spring.version>3.1.2.RELEASE</spring.version>     
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <repositories>
        <repository>
            <id>JBoss repository</id>
            <url>http://repository.jboss.com/maven2/</url>
        </repository>
    </repositories>

    <dependencies>

        <!-- PostgeSQL -->
        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.1-901.jdbc4</version>
        </dependency>    

        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- JSP dependacy -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>

        <!-- Apache Commons Upload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.2.2</version>
        </dependency>

        <!-- Apache Commons Upload -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1-b01</version>
        </dependency> 

        <!-- Ibatis -->  
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.0</version>
        </dependency>  
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.0</version>
        </dependency>        
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- JUnit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>MailClient</artifactId>
            <version>${project.version}</version>
        </dependency>     

    </dependencies>

the applicationContext.xml (used for test)

<context:component-scan base-package="it.infora.suap" />

        <!-- enable autowire -->
    <context:annotation-config  />

    <!-- transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>    

        <!-- enable transaction demarcation with annotations -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!-- Declare a datasource that has pooling capabilities -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="org.postgresql.Driver" p:url="jdbc:postgresql://localhost:5432/suap"
        p:username="userSuap" p:password="us3rsu@p" p:defaultAutoCommit="false" />


        <!-- define the SqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="typeAliasesPackage" value="it.infora.suap.model"/>
            <!--property name="configLocation" value="META-INF/mybatis-config.xml" /-->
            <property name="typeHandlersPackage" value="it.infora.suap.handler"/>

        </bean>        

        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
         <constructor-arg index="0" ref="sqlSessionFactory" />
        </bean>        

        <!-- scan for mapper interface files and let them be autowired -->
     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
      <property name="basePackage" value="it.infora.suap.persistence" />
     </bean> 

my model class

@Component
public class MailReceiverAccountBean implements MailReceiverAccount {

    private Integer id;
    private String username;
    private String password;
//    private String email;
    private String serverAddress;
    private Integer serverPort;
    private MailProtocol mailProtocol;
//    private String name;
    private Boolean encrypted;
    private MailEncryptionType encryptionType;
    private String accountName;

omitted getter and setter ....

the mapper class

@Repository
public interface MailReceiverAccountMapper {

    @Insert("INSERT INTO email_account(username, password, server_address, server_port, mail_protocol, account_name, encrypted, encryption_type)"
            + " VALUES(#{username}, #{password}, #{serverAddress}, #{serverPort}, #{mailProtocol, javaType=MailProtocol.class, jdbcType=JdbcType.VARCHAR, typeHandler=MailProtocolEnumHandler.class},"
            + " #{accountName}, #{encrypted}, #{encryptionType, javaType=MailProtocol.class, jdbcType=JdbcType.VARCHAR, typeHandler=MailEncryptionTypeEnumHandler.class})")
//    @Options(useGeneratedKeys = true, keyProperty = "id")
    public void insertEmailAccount(MailReceiverAccountBean mailReceiverAccountBean);

.........

the service class

@Service("mailReceiverAccountService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class MailReceiverAccountService implements DaoService<MailReceiverAccountBean>{

    @Autowired
    private SqlSession sqlSession;

    @Override
    public void save(MailReceiverAccountBean entity) {
        MailReceiverAccountMapper mailReceiverAccountMapper = sqlSession.getMapper(MailReceiverAccountMapper.class);
        mailReceiverAccountMapper.insertEmailAccount(entity);
    }
       ............

the test class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:testApplicationContext.xml")
public class MailReceiverAccountServiceTest {

    @Autowired
    private MailReceiverAccountService mailReceiverAccountService;


    /**
     * Test of save method, of class EmailAccountService.
     */
    @Test
    public void testSave() {
        System.out.println("save");
        MailReceiverAccountBean ea = this.getFilledEntity();
        mailReceiverAccountService.save(ea);

        Assert.assertTrue(ea.getId() != 0);

        MailReceiverAccountBean created = mailReceiverAccountService.findById(ea.getId());
        Assert.assertNotNull(created);
        Assert.assertEquals(ea, created);        
    }

What's wrong? Am i loosing some configurations? thanks in advance

andrea

回答1:

Change the autowired code from

@Autowired
private MailReceiverAccountService mailReceiverAccountService;

to

@Autowired
private DaoService mailReceiverAccountService;

If you have multiple DaoService implementation classes, use @Qualifier with @Autowired to distinguish them.



回答2:

solved ... the problem was i was trying to autowired a concrete bean without an interface

thanks all for replies :-)

andrea



回答3:

In the context xml, you are not providing the base package for scanning the annotated components. Hence you service class is not scanned and autowired. Please add this entry into the context

<context:annotation-config />
<context:component-scan base-package="basepackage" />