117

I've started my project by creating entities, services and JUnit tests for services using Spring and Hibernate. All of this works great. Then I've added spring-mvc to make this web application using many different step-by-step tutorials, but when I'm trying to make Controller with @Autowired annotation, I'm getting errors from Glassfish during deployment. I guess that for some reason Spring doesn't see my services, but after many attempts I still can't handle it.

Tests for services with

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml"})

and

@Autowired
MailManager mailManager;

works properly.

Controllers without @Autowired too, I can open my project in web browser without trouble.

/src/main/resources/beans.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">

    <context:property-placeholder location="jdbc.properties" />
    
    <context:component-scan base-package="pl.com.radzikowski.webmail">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    
    <!--<context:component-scan base-package="pl.com.radzikowski.webmail.service" />-->
    
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    
    <!-- Persistance Unit Manager for persistance options managing -->
    <bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="defaultDataSource" ref="dataSource"/>
    </bean>

    <!-- Entity Manager Factory for creating/updating DB schema based on persistence files and entity classes -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
        <property name="persistenceUnitName" value="WebMailPU"/>
    </bean>

    <!-- Hibernate Session Factory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--<property name="schemaUpdate" value="true" />-->
        <property name="packagesToScan" value="pl.com.radzikowski.webmail.domain" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            </props>
        </property>
    </bean>
    
    <!-- Hibernate Transaction Manager -->
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <!-- Activates annotation based transaction management -->
    <tx:annotation-driven transaction-manager="txManager"/>

</beans>

/webapp/WEB-INF/web.xml

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="WebApp_ID" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Spring Web MVC Application</display-name>
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

/webapp/WEB-INF/mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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-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">
    
    <context:component-scan base-package="pl.com.radzikowski.webmail" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    
    <mvc:annotation-driven/>
    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
</beans>

pl.com.radzikowski.webmail.service.AbstractManager

package pl.com.radzikowski.webmail.service;

import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Master Manager class providing basic fields for services.
 * @author Maciej Radzikowski <maciej@radzikowski.com.pl>
 */
public class AbstractManager {

    @Autowired
    protected SessionFactory sessionFactory;

    protected final Logger logger = Logger.getLogger(this.getClass());

}

pl.com.radzikowski.webmail.service.MailManager

package pl.com.radzikowski.webmail.service;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@Transactional
public class MailManager extends AbstractManager {
    // some methods...
}

pl.com.radzikowski.webmail.HomeController

package pl.com.radzikowski.webmail.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import pl.com.radzikowski.webmail.service.MailManager;

@Controller
@RequestMapping("/")
public class HomeController {

    @Autowired
    public MailManager mailManager;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String homepage(ModelMap model) {
        return "homepage";
    }

}

Error:

SEVERE: Exception while loading the app
SEVERE: Undeployment failed for context /WebMail
SEVERE: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'homeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public pl.com.radzikowski.webmail.service.MailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [pl.com.radzikowski.webmail.service.MailManager] 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)}

Sorry for a lot of code, but I don't know what can cause that error anymore.

Added

I've created the interface:

@Component
public interface IMailManager {

added implements:

@Component
@Transactional
public class MailManager extends AbstractManager implements IMailManager {

and changed autowired:

@Autowired
public IMailManager mailManager;

But it still throws errors (also when I've tried with @Qualifier)

..Could not autowire field: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager...

I've tried with different combinations of @Component and @Transactional too.

Shouldn't I include beans.xml in web.xml somehow?

shaedrich
  • 5,457
  • 3
  • 26
  • 42
Radzikowski
  • 2,377
  • 4
  • 27
  • 39

23 Answers23

96

You should autowire interface AbstractManager instead of class MailManager. If you have different implemetations of AbstractManager you can write @Component("mailService") and then @Autowired @Qualifier("mailService") combination to autowire specific class.

This is due to the fact that Spring creates and uses proxy objects based on the interfaces.

Patison
  • 2,591
  • 1
  • 20
  • 33
  • 2
    Thank you but it still doesn't work (same error). I added changes in post. Maybe I don't include / search something in my project properly? – Radzikowski Dec 02 '13 at 20:38
  • I'm wondering if there is a way to do something like `@Autowired AbstractManager[] abstractManagers` that contains all its implementations. – WoLfPwNeR Jan 08 '16 at 00:01
  • @WoLfPwNeR It should work exactly as you wrote. See [link](http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/beans.html#beans-autowired-annotation) – Patison Jan 11 '16 at 08:31
  • Why not `MailManager`? – Alex78191 Apr 13 '18 at 10:55
  • 1
    I have two `@Service` classes implementing the same interface. Both are `@Autowired` in another class. Initially it caused the same problem as the original post when I used the specific class type. Following this answer, I changed to use Interface type with different `@Qualifier("myServiceA")` and `@Qualifier("myServiceB")`, and the problem was resolved. Thanks! – xialin Apr 25 '19 at 19:36
34

I had this happen because my tests were not in the same package as my components. (I had renamed my component package, but not my test package.) And I was using @ComponentScan in my test @Configuration class, so my tests weren't finding the components on which they relied.

So, double check that if you get this error.

mooreds
  • 4,932
  • 2
  • 32
  • 40
10

The thing is that both the application context and the web application context are registered in the WebApplicationContext during server startup. When you run the test you must explicitly tell which contexts to load.

Try this:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml", "/mvc-dispatcher-servlet.xml"})
emd
  • 740
  • 4
  • 12
  • 1
    How to do it if a am using Spring Boot? – Alex78191 Apr 13 '18 at 11:16
  • I forget about configuring component scan for maven dependencies and struggle with this like once a year. – b15 Sep 17 '20 at 12:35
  • 1
    If you're talking about the application itself and not integration tests, for Spring boot you can do it like this: `@SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })` – b15 Sep 17 '20 at 12:37
8

I was facing the same issue while auto-wiring the class from one of my jar file. I fixed the issue by using @Lazy annotation:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;

Ved Singh
  • 705
  • 9
  • 4
  • Weirdly enough, I needed this when migrating from Hibernate v4.3/Spring v4.3 to Hibernate v5.4/Spring v5.3... the solution was either to add this `@Lazy`, or to enable the DEBUG logs for `org.springframework.data.repository` ?!? timing / race-condition issue I guess? (adding logs slowed things down enough to delay things to fix the issue?) sooo weird – xav Nov 26 '21 at 14:10
  • How does using @Lazy solve this particular problem? I've had the same problem and it helped - I just don't understand how. – pidabrow Jun 14 '23 at 08:03
7

This may help you:

I have the same exception in my project. After searching while I found that I am missing the @Service annotation to the class where I am implementing the interface which I want to @Autowired.

In your code you can add the @Service annotation to MailManager class.

@Transactional
@Service
public class MailManager extends AbstractManager implements IMailManager {
shaedrich
  • 5,457
  • 3
  • 26
  • 42
Akshay Pethani
  • 2,390
  • 2
  • 29
  • 42
7

Faced the same issue in my spring boot application even though I had my package specific scans enabled like

@SpringBootApplication(scanBasePackages={"com.*"})

But, the issue was resolved by providing @ComponentScan({"com.*"}) in my Application class.

Patrick W
  • 1,485
  • 4
  • 19
  • 27
Rajish Nair
  • 71
  • 1
  • 2
6

Spent much of my time with this! My bad! Later found that the class on which I declared the annotation Service or Component was of type abstract. Had enabled debug logs on Springframework but no hint was received. Please check if the class if of abstract type. If then, the basic rule applied, can't instantiate an abstract class.

James Jithin
  • 10,183
  • 5
  • 36
  • 51
3

Correct way shall be to autowire AbstractManager, as Max suggested, but this should work fine as well.

@Autowired
@Qualifier(value="mailService")
public MailManager mailManager;

and

@Component("mailService")
@Transactional
public class MailManager extends AbstractManager {
}
Timeless
  • 7,338
  • 9
  • 60
  • 94
Abhishek Anand
  • 1,940
  • 14
  • 27
3

Can you try annotating only your concrete implementation with @Component? Maybe the following answer could help. It is kind of a similar problem. I usually put Spring annotations in the implementation classes.

https://stackoverflow.com/a/10322456/2619091

Community
  • 1
  • 1
yamilmedina
  • 3,315
  • 2
  • 20
  • 28
3

The solution that worked for me was to add all the relevant classes to the @ContextConfiguration annotation for the testing class.

The class to test, MyClass.java, had two autowired components: AutowireA and AutowireB. Here is my fix.

@ContextConfiguration(classes = {MyClass.class, AutowireA.class, AutowireB.class})
public class MyClassTest {
...
}
Raphael
  • 441
  • 1
  • 6
  • 12
  • This was a lifesaver and resolved my issue. Incase it helps anyone, I was having same issue in my ControllerTest class with the jackson ObjectMapper dependency not being found, which I had as autowired. The above solution of adding the ObjectMapper with @ContextConfiguration resolved my issue. – VC2019 Mar 29 '21 at 17:34
2

My guess is that here

<context:component-scan base-package="pl.com.radzikowski.webmail" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

all annotations are first disabled by use-default-filters="false" and then only @Controller annotation enabled. Thus, your @Component annotation is not enabled.

shaedrich
  • 5,457
  • 3
  • 26
  • 42
LoBo
  • 212
  • 1
  • 2
  • 9
2

I ran in to this recently, and as it turned out, I've imported the wrong annotation in my service class. Netbeans has an option to hide import statements, that's why I did not see it for some time.

I've used @org.jvnet.hk2.annotations.Service instead of @org.springframework.stereotype.Service.

kazmer
  • 501
  • 4
  • 12
1
  • One reason BeanB may not exist in the context
  • Another cause for the exception is the existence of two bean
  • Or definitions in the context bean that isn’t defined is requested by name from the Spring context

see more this url:

http://www.baeldung.com/spring-nosuchbeandefinitionexception

zohreh
  • 913
  • 1
  • 7
  • 9
1
 <context:component-scan base-package="com.*" />

same issue arrived , i solved it by keeping the annotations intact and in dispatcher servlet :: keeping the base package scan as com.*. this worked for me.

Ali
  • 3,346
  • 4
  • 21
  • 56
1

Instead of @Autowire MailManager mailManager, you can mock the bean as given below:

import org.springframework.boot.test.mock.mockito.MockBean;

::
::

@MockBean MailManager mailManager;

Also, you can configure @MockBean MailManager mailManager; separately in the @SpringBootConfiguration class and initialize like below:

@Autowire MailManager mailManager
biniam
  • 8,099
  • 9
  • 49
  • 58
Barani r
  • 2,119
  • 1
  • 25
  • 24
1

This also happened to me when I had two methods with the same name marked @Bean in different @Configuration classes. It appears that one of the declarations was overriding the other.

xilef
  • 2,199
  • 22
  • 16
0

If you are testing your controller. Don't forget to use @WebAppConfiguration on your test class.

Joao Luiz Cadore
  • 2,656
  • 1
  • 15
  • 11
0

I had this happen because I added an autowired dependency to my service class but forgot to add it to the injected mocks in my service unit test.

The unit test exception appeared to report a problem in the service class when the problem was actually in the unit test. In retrospect, the error message told me exactly what the problem was.

Curtis Yallop
  • 6,696
  • 3
  • 46
  • 36
0

I had faced the same problem, Issue SOlved using below steps:

  1. Check the class/Interface that you are auto wiring
  2. For Interface Business logic we should use @service when it extends the Interface method.
  3. For Dao that is a Database handling class we should use @Repository.

→ We can use @Service, @Repository and @Component annotation effectively and solve this issue very fast.

shaedrich
  • 5,457
  • 3
  • 26
  • 42
0

if you are testing the DAO layer you must use @Autowire annotation like this:

@Autowired
private FournisseurDao fournisseurDao;

Don't inject a repository element in the constructor

lkatiforis
  • 5,703
  • 2
  • 16
  • 35
0

I've reproduced similar issue in multi-module project w/ No qualifying bean of type like:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.stockclient.repository.StockPriceRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

and the reason for this error was missing annotation @EnableJpaRepositories in my specific use case.

To clarify: this annotation needs to be added for enabling auto configuration support for Spring Data JPA required to know the path of JPA repositories. By default, it will scan only the main application package and its sub packages for detecting the JPA repositories.

For more details you can refer, for instance, to this article.

invzbl3
  • 5,872
  • 9
  • 36
  • 76
0

Was configuring a non-SpringBoot, non-JPA, Hibernate application and the error was seen with injecting a DAO class implementation defined with @Repository.

Moving the declaration from @Repository to @Component worked. Remember that you would lose some features as mentioned here

James Jithin
  • 10,183
  • 5
  • 36
  • 51
0

As an industrial standard or the best practice is to use Interfaces which are implemented by java classes, like Controller, service and repository. in my case i have @Autowired service class, that's what bringing the error.

Fixed by @Autowired service interface, instead of service class. and don't forget to add @Service for your service class.