Spring Autowire fails with No qualifying bean of type found for dependency error
autowired, spring, struts2
Solution
Change `@Service("CommonSQLService")` to `@Service("commonSQLService")` or you can just use `@Service` if you're not implementing the `CommonSQLService` interface anywhere else.
Problem
Here's my scenario. My project is using Spring (3.2.3.RELEASE), Struts2 (2.3.14.3) and JPA (2.0). We have a project (let's call it project A) that contains various entities and common classes. We use project A to generate a .jar file so that other projects can use these classes. In project A we've used the Spring stereotypes: @Component. @Service or @Repository for those classes we want Spring to inject. Whenever we try to inject beans from the jar, we get an error similar to: No qualifying bean of type [com.ceiwc.bc.commonsql.service.CommonSQLService] 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)} Could not autowire field: private com.ceiwc.bc.commonsql.service.CommonSQLService com.ceiwc.ma.mvc.action.LoginAction.commonSQLService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.ceiwc.bc.commonsql.service.CommonSQLService] 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)} Error creating bean with name 'com.ceiwc.ma.mvc.action.LoginAction': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.ceiwc.bc.commonsql.service.CommonSQLService com.ceiwc.ma.mvc.action.LoginAction.commonSQLService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.ceiwc.bc.commonsql.service.CommonSQLService] 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)} Unable to instantiate Action, com.ceiwc.ma.mvc.action.LoginAction, defined for 'doLogin' in namespace '/Login'Error creating bean with name 'com.ceiwc.ma.mvc.action.LoginAction': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.ceiwc.bc.commonsql.service.CommonSQLService com.ceiwc.ma.mvc.action.LoginAction.commonSQLService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.ceiwc.bc.commonsql.service.CommonSQLService] 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)} We are using Java configuration for Spring. Here is our configuration class: ``` package com.zzz.bc.config; @Configuration @ImportResource({"/WEB-INF/spring/spring-config.xml"}) @ComponentScan(basePackages = "com.zzz") public class ApplicationConfig { @Bean public JavaMailSender mailSender() { JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); mailSender.setHost(${app.mail.host}); return mailSender; } } package com.zzz.bc.config; @Configuration @EnableTransactionManagement @Import(ApplicationConfig.class) @PropertySource({"classpath:db.properties"}) public class DataConfig { @Autowired Environment environment; @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); return transactionManager; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { String[] packagesToScan = {environment.getProperty("db.packagesToScan1"), environment.getProperty("db.packagesToScan2")}; Map<String, Object> jpaProperties = new HashMap<String, Object>(); jpaProperties.put("eclipselink.weaving", "false"); LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource()); entityManagerFactoryBean.setPackagesToScan(packagesToScan); entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter()); entityManagerFactoryBean.setJpaPropertyMap(jpaProperties); return entityManagerFactoryBean; } @Bean public DriverManagerDataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(environment.getProperty("db.driver")); dataSource.setUrl(environment.getProperty("db.url")); dataSource.setUsername(environment.getProperty("db.username")); dataSource.setPassword(environment.getProperty("db.password")); return dataSource; } @Bean public JpaVendorAdapter vendorAdapter() { EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter(); vendorAdapter.setDatabase(Database.ORACLE); vendorAdapter.setShowSql(true); return vendorAdapter; } @Bean public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor(); } } ``` We have @ComponentScan set to check to bean in the package of com.zzz. In project B, we have a Struts2 Action that we want to inject a bean from project A. Here is a snippet of the class from project B: ``` @SuppressWarnings("rawtypes") @Service("CommonSQLService") public class CommonSQLServiceImpl implements CommonSQLService { @Autowired CommonSQLDao cdao; @Override public Policy getPolicyById(String policyNo) { return cdao.getPolicyById(policyNo); } @Override public Policy getPolicy(Policy parmRec) { return cdao.getPolicy(parmRec); } @Override public ArrayList<Policy> getPolicies(String policyNo) { return cdao.getPolicies(policyNo); } @Override public List<Policy> getPolicies(Policy parmRec){ return cdao.getPolicies(parmRec); } } ``` Here is our action (removed getters/setters): ``` package com.zzz.ma.mvc.action; @SuppressWarnings("serial") @Component @Scope("prototype") @Namespace("/Login") public class LoginAction extends ActionParent { @Autowired private IUserService userService; //Contained in project B @Autowired private CommonSQLService commonSQLService; //What's autowired from project A private User user; private String updateFlag; private Integer parentMenuId; private IwifWebNavmenuItem record; public static final String LOGIN_STR = "login"; @Action(value = "doLogin", results = { @Result(name = "success", location = "/pages/login.jsp") }) public String login() { updateFlag = "Y"; return SUCCESS; } @Action(value = "validate", results = { @Result(name = "success", location = "/BrowseOptions/showOptions", type = "redirect"), @Result(name = "login", location = "/pages/login.jsp") }) public String validateUser() { if (updateFlag == null) { session.remove(LOGIN_STR); return LOGIN; } if (userService.validateUser(user.getUsername(), user.getPassword()) == null) { addActionError(getText("invalid.user")); return LOGIN; } session.put(LOGIN_STR, user.getUsername()); return SUCCESS; } @Action(value = "logout", results = { @Result(name = "success", location = "/pages/login.jsp") }) public String logout() { updateFlag = StringUtils.EMPTY; session.invalidate(); return SUCCESS; } } ``` Whenever we try to do this autowire, we get an error like the one listed above. What are we missing? Can't classes contained in a jar file with Spring Stereotypes be autowired? Thanks for you help in advance!