2
votes

having looked at several similar problems here and applied the logic to my situation, I'm still stumped with a dependency injection failure in my Spring/JPA app. The premises of the application are:

  • Use Annotation based JPA2 to cut back on xml config;
  • Autogenerate DAOs from a single interface/implementation using @Autowire for each DAO type as per reference tutorial here;

Here's the fatal error:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'exampleInstanceBO': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.***.dao.IGenericDAO com.***.bo.ExampleInstanceBO.dao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.***.dao.IGenericDAO] 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), @org.springframework.beans.factory.annotation.Qualifier(value=IGenericDAO)}

... which is caused further down the chain by:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.***.dao.IGenericDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.

It's called in the following service class:

ExampleInstanceBO:


    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Service;

    import com.***.dao.*;
    import com.***.entity.*;

    @Service
    public class ExampleInstanceBO {
        @Autowired
        @Qualifier(value="IGenericDAO")
        IGenericDAO dao;

        public void setDao( final IGenericDAO daoToSet ){
            dao = daoToSet;
            dao.setClazz( ExampleInstance.class );
        }

            //
    }

 

IGenericDAO is as follows:

IGenericDAO:


    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;

    @Component("IGenericDAO")
    public interface IGenericDAO {
        public void setClazz(final Class clazzToSet);
        public T findById( final Long id );
        public List findAll();
        public void save( final T entity );
        public void update( final T entity );
        public void delete( final T entity );
        public void deleteById( final Long entityId );
    }

Its implementation is as follows:

GenericDAO


    import java.io.Serializable;  

    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Repository;

    @Repository
    @Scope("prototype")
    public class GenericDAO extends AbstractDAO implements IGenericDAO{
       //empty, because most functionality in abstract class AbstractDAO
    }

AbstractDAO


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

    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    import org.springframework.stereotype.Service;
    /**
     * @author ----
     *
     */
    @Service
    public abstract class AbstractDAO {
           private Class clazz;
           @PersistenceContext
           EntityManager entityManager;
           public void setClazz( final Class clazzToSet ){
              this.clazz = clazzToSet;
           }
           public T findById( final Long id ){
              return entityManager.find( clazz, id );
           }
           public List findAll(){
              return entityManager.createQuery( "from " + clazz.getName() )
               .getResultList();
           }

    // other save/delete/update etc. methods here
    }

The above is based on the discussion here which takes quite a lot for granted in terms of config and dependencies. Here are my config and pom files which quite possibly are contributing to the confusion, as they've evolved while I've been trying to sort this out.

beanDefinitions.xml

<jpa:repositories base-package="com.***" />
<context:component-scan base-package="com.***" />

<bean class="org.springframework.orm.jpa.JpaTransactionManager"
  id="transactionManager">
  <property name="entityManagerFactory" 
      ref="entityManagerFactory" />
  <property name="jpaDialect">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
  </property>
</bean>

<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="packagesToScan" value="***" />
  <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
      <property name="generateDdl" value="true" />
      <property name="database" value="HSQL" />
    </bean>
  </property>
</bean>

<bean 
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location">
        <value>database.properties</value>
    </property>
</bean>

<bean id="dataSource" 
         class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <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>
</beans>

and finally, the pom.xml:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>maven_projects</groupId>
    <artifactId>***</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>***</name>
    <description>spring 3 plus maven</description>
    <packaging>war</packaging>
    <properties>
        <org.springframework.version>3.1.3.RELEASE</org.springframework.version>
        <hibernate.version>4.1.0.Final</hibernate.version>
        <mysql.version>5.1.13</mysql.version>
        <junit.version>4.7</junit.version>
        <slf4j.version>1.7.0</slf4j.version>
    </properties>
    <dependencies>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- logging -->
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>jcl-over-slf4j</artifactId>
          <version>${slf4j.version}</version>
       </dependency>
       <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>${slf4j.version}</version>
       </dependency>
       <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>${slf4j.version}</version>
       </dependency>
       <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.14</version>
       </dependency>
        <!-- ORM/DB -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
            <!-- perhaps using scope = provided, as this will often
             be present on the app server -->
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <!-- or hibernate-entitymanager if you use jpa -->
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
                <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.2.0.RELEASE</version>
        </dependency>
        <!-- 
            default Jave EE jars don't include code necessary for
         bytecode enhancement so we use these instead --> 
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <version>1.0.0.Final</version>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>

        <!-- Jersey (RESTful web services -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.8</version>
        </dependency>
        <!-- Jersey + Spring -->
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-spring</artifactId>
            <version>1.8</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-web</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
    </dependencies>

    <!-- 
        Required for J2EE dependencies, see here: 
        http://www.ninthavenue.com.au/java-lang-classformaterror-exception-with-eclipselink-static-weaving-solved   
     -->
    <repositories>
        <repository>
        <id>repository.jboss.org-public</id>
        <name>JBoss repository</name>
        <url>https://repository.jboss.org/nexus/content/groups/public</url>
        </repository>
    </repositories>


</project>

** UPDATE **

Thanks, tried that, GenericDAO now looks like this:


    // @Component("GenericDAO") 
    @Repository("GenericDAO") 
    @Scope("prototype") 
    public class GenericDAO extends AbstractDAO implements IGenericDAO{
     // 
    }

Using either the Component or the Repository annotation, still the same result. Looking at the log output, the beans that are generated are as follows:

... GenericDAO ... But it's looking for IGenericDAO - when I change to @Repository("IGenericDAO") it throws a null pointer exception, - baffled!

UPDATE #2 - datasource 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:jpa="http://www.springframework.org/schema/data/jpa"
   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/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<!--<jpa:repositories base-package="***" />-->
<context:component-scan base-package="***" />

<bean class="org.springframework.orm.jpa.JpaTransactionManager"
  id="transactionManager">
  <property name="entityManagerFactory" 
      ref="entityManagerFactory" />
  <property name="jpaDialect">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
  </property>
</bean>

<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="packagesToScan" value="***" />
  <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
      <property name="generateDdl" value="true" />
      <property name="database" value="HSQL" />
    </bean>
  </property>
</bean>

<bean 
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location">
        <value>database.properties</value>
    </property>
</bean>

<bean id="dataSource" 
         class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <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>
</beans>
2
Try removing the scope("prototype") from GenericDAO. Add your spring logs to your question please.Καrτhικ
Why reinvent the things already working in Spring Data JpaBoris Treukhov
@BorisTreukhov - not having tried it, the impression I get of Spring Data JPA is it does a little too much to take the boilerplate code away - I want to be able to add custom methods to the DAO implementations in order not to go all the way through the object hierarchy for some of the more complex queries. Might be that I end up taking your advice in the end, but for now I want to preserve some flexibility if I can. ThxtacticAl
I don't think that things are that bad in Spring Data JPA stackoverflow.com/questions/11880924/… I believe that it's the business domain that matters, and inventing a custom framework is unlikely a good way to start using Spring(and is a tremendous risk if you are doing a project, and even if it will work it unlikely will be a thoroughly tested framework) - I think that the Spring Source developers know what they are doing, and so do many system integrators, who are using this framework. That is my humble opinion of course.Boris Treukhov
is it a web app? How is context component scan declared, what are all those stars supposed to mean, are they in the actual config?Boris Treukhov

2 Answers

1
votes

Put the @Component annotation on your GenericDAO, not the interface.

0
votes

I see a few things which dont seem right.

  • Please remove the @Component("IGenericDAO") annotation on the interface. It doesn't make sense. You set the ID on the implementation, not the interface.
  • In the ExampleInstanceBO class, please remove the qualifier you added on the IGenericDao. As long as you only have one bean of that type on the classpath, you dont the qualifier for now.
  • I am very skeptical of the "base-package="***"" component scan configuration. Please make sure it works by debugging your application. Start a remote debugging session and look into your application context bean map to see if the bean is actually being picked up.
  • You can also try to add the full package name explicitly in the component scan to make sure its being picked up.

Good luck ;)