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>