0

What am I missing? I am trying to create a basic SpringMVC application using Hibernate. I have another SpringMVC application that I model it after and it works. I have apparently missed something and I am at a loss. Any help here would be much appreciated. Just another pair of eyes might solve the problem. Maybe I am blind.

Basically the error is telling me that I cannot create customerService bean in my controller because the customerDao bean cannot be located and therefore cannot be injected into the service.

When I use Intellij I am able to follow the bean references and everything appears to be wired up correctly but when I run in tomcat6 or tomcat7 get the following errors:

Sep 26, 2013 10:13:02 AM org.springframework.web.context.ContextLoader initWebApplicationContext
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mydomain.dao.CustomerDao com.mydomain.service.CustomerService.customerDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mydomain.dao.CustomerDao] 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:288)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1122)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4701)
        at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5204)
        at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5199)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
        at java.util.concurrent.FutureTask.run(FutureTask.java:166)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:724)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mydomain.dao.CustomerDao com.mydomain.service.CustomerService.customerDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mydomain.dao.CustomerDao] 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:514)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
        ... 21 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mydomain.dao.CustomerDao] 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:986)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:856)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
        ... 23 more
Sep 26, 2013 10:13:02 AM org.apache.catalina.core.StandardContext startInternal

Code as follows:

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.mydomain.config.WebConfig</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.mydomain.config.WebConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

WebConfig.java

package com.mydomain.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;


@EnableWebMvc
@Configuration
@Import({DaoConfig.class, ServiceConfig.class, ControllerConfig.class})
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public Validator getValidator(){
        return new LocalValidatorFactoryBean();
    }

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setViewClass(JstlView.class);
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");

        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

DaoConfig.java

package com.mydomain.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan({"com.mydomain.dao", "com.mydomain.service"})
public class DaoConfig {
    @Bean
    public LocalSessionFactoryBean getSessionFactory(){
        final LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(getDataSource());
        sessionFactoryBean.setPackagesToScan(new String[]{"com.mydomain.domain"});
        sessionFactoryBean.setHibernateProperties(hibernateProperties());
        return sessionFactoryBean;
    }

    @Bean
    public DataSource getDataSource(){
        final DriverManagerDataSource dmds = new DriverManagerDataSource();
        dmds.setDriverClassName("com.mysql.jdbc.Driver");
        dmds.setUsername("root");
        dmds.setPassword("");
        dmds.setUrl("jdbc:mysql://localhost/commandsearch");
        return dmds;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        final HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(getSessionFactory().getObject());

        return txManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    final Properties hibernateProperties() {
        return new Properties() {
            {
                setProperty("hibernate.hbm2ddl.auto", "update");
                setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                setProperty("hibernate.show_sql", "true");
            }
        };
    }
}

IAbstractDao.java

package com.mydomain.dao;

import java.io.Serializable;
import java.util.List;

public interface IAbstractDao <T extends Serializable> {
    T findOne(final long id);
    List<T> findAll();
    void save(final T t);
    void delete(final T t);
    void deleteById(final long id);
}

AbstractHibernateDao.java

package com.mydomain.dao;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class AbstractHibernateDao<T extends Serializable> implements IAbstractDao<T> {
    protected Class<T> entityClass;
    protected final Log logger = LogFactory.getLog(getClass()); 

    protected AbstractHibernateDao(Class<T> entityClass){
        this.entityClass = entityClass;
    }

    @Autowired
    private SessionFactory sessionFactory;

    protected final Session getCurrentSession(){
        return sessionFactory.getCurrentSession();
    }
    @Override
    public T findOne(final long id) {
        return ((T) getCurrentSession().get(entityClass, id));
    }

    @Override
    public List<T> findAll() {
        return (List<T>)getCurrentSession().createQuery("from " + entityClass.getName()).list();
    }

    @Override
    public void save(final T t) {
        getCurrentSession().saveOrUpdate(t);
    }

    @Override
    public void delete(final T t) {
        getCurrentSession().delete(t);
    }

    @Override
    public void deleteById(final long id) {
        final T entity = findOne(id);
        delete(entity);
    }
}

CustomerDao.java

package com.mydomain.dao;

import org.springframework.stereotype.Repository;

import com.mydomain.domain.Customer;

@Repository
public class CustomerDao extends AbstractHibernateDao<Customer> {
    public CustomerDao(){
        this(Customer.class);
    }

    public CustomerDao(Class<Customer> entityClass){
        super(entityClass);
    }
}

ServiceConfig.java

package com.mydomain.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.mydomain.service"})
public class ServiceConfig {

}

AbstractService.java

package com.mydomain.service;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;

import com.mydomain.dao.IAbstractDao;

@Transactional
public abstract class AbstractService<T extends Serializable> {
    protected final Log logger = LogFactory.getLog(getClass());

    public T findOne(final long id) {
        return getDao().findOne(id);
    }

    public List<T> findAll() {
        return getDao().findAll();
    }

    public void save(final T entity) {
        getDao().save(entity);
    }

    public void delete(final T entity) {
        getDao().delete(entity);
    }

    public void deleteById(final long entityId) {
        getDao().deleteById(entityId);
    }

    protected abstract IAbstractDao<T> getDao();
}

CustomerService.java

package com.mydomain.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mydomain.dao.CustomerDao;
import com.mydomain.dao.IAbstractDao;
import com.mydomain.domain.Customer;

@Service
@Transactional
public class CustomerService extends AbstractService<Customer>{

    @Autowired
    private CustomerDao customerDao;

    @Override
    protected IAbstractDao<Customer> getDao() {
        return customerDao;
    }
}
John
  • 763
  • 1
  • 10
  • 21
  • You should split your configuration, currently you are duplicating all bean instances because both the `ContextLoaderListener` and `DispatcherServlet` load the same configuration. – M. Deinum Sep 26 '13 at 17:40

1 Answers1

0

Your immediate problem is this

package com.mydomain.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.mydomain.service"})
public class ServiceConfig {

}

You're scanning your @Service class but you have nothing in that context that gives you a CustomerDao bean available for injection so it fails with the exception you have.


There are a bunch of other things wrong with your configuration. Your DaoConfig scans both dao and service packages. This on its own is not bad, but you have all the other XConfig classes that are redundant.

Also, your web.xml configuration is going to create 2 WebConfig contexts, one for the DispatcherServlet and one for the ContextLoaderListener.

Your ContextLoaderListener should load the root context and the DispatcherServlet should load the servlet context.

For example, the DispatcherServlet should load the WebConfig as such

@EnableWebMvc
@Configuration
@Import(ControllerConfig.class)
public class WebConfig extends WebMvcConfigurerAdapter {

Note it only @Imports ControllerConfig.

Your ContextLoaderListener should load the application config as such

@Configuration
@EnableTransactionManagement
@ComponentScan({"com.mydomain.dao", "com.mydomain.service"}, ...)
public class ApplicationConfig {
    // all the @Bean methods from each of your other XxxConfig classes
}

If you want to modularize it further, keep in mind that @Import only works on the @Configuration class or context that is using it, not on the context being imported.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • The DaoConfig is scanning com.mydomain.dao package, which should create the CustomerDao bean. I don't need a reference in the ServiceConfig. The CustomerService class has the Autowire reference to CustomerDao. As far as DaoConfig scanning both packages, I have tried it with and without scanning the service package. I have this web.xml working in a different application with small differences. I don't remember off the top of my head why I did this but there was something that needed both in the other application – John Sep 26 '13 at 17:49
  • @John The beef is that `DaoConfig` is using `@Import(ServiceConfig.class)` which is trying to load a context with a `@Service` class that requires injection of a `CustomerDao` bean that doesn't exist in _that_ context. Your contexts are just not configured correctly. Read my answer carefully. – Sotirios Delimanolis Sep 26 '13 at 17:51
  • I am not sure how DaoConfig is using @Import(ServiceConfig.class) WebConfig is doing all of the importing and each of the configs are handling their own ComponentScan. I have this setup working in another application. The only difference I have in the other application is I have an interface for each dao. I skipped that here. Intellij is able to follow the bean declarations in the IDE. I did attempt splitting the ContextLoader and DispatchServlet, I was just trying to avoid declaring each bean. – John Sep 26 '13 at 18:49
  • @John My mistake, your `WebConfig` is doing that. – Sotirios Delimanolis Sep 26 '13 at 18:50