I'm using constructor-based dependency injection to inject a javax.inject.Provider<T> to a service. With Spring Framework (4.2.5), NoSuchBeanDefinitionException will be thrown saying "No qualifying bean of type [T] found for dependency. Why is T expected by Spring while injecting javax.inject.Provider<T>?
Here's the sample code:
Provider:
import javax.inject.Provider;
public class MessageProvider implements Provider<String> {
#Override
public String get() {
return "Hello!";
}
}
Service:
import javax.inject.Inject;
import javax.inject.Provider;
public class GreetingService {
private final String message;
#Inject
GreetingService(Provider<String> provider) {
// GreetingService(MessageProvider provider) { // this works!
this.message = provider.get();
}
public String greeting() {
return message;
}
}
Test:
import org.junit.Test;
import static org.junit.Assert.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class GreetingServiceTest {
#Test
public void testSomeMethod() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(MessageProvider.class);
ctx.register(GreetingService.class);
ctx.refresh();
GreetingService bean = ctx.getBean(GreetingService.class);
String message = bean.greeting();
assertNotNull(message);
}
}
And here's the error message:
Error creating bean with name 'greetingService': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [GreetingService]: Constructor threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
You're question is a bit ambiguous. Are you asking why Spring needs a bean that can create a T or are you asking why Spring isn't injecting an instance of your MessageProvider class?
If your question is the former then the problem you are facing is that Provider<T> is an interface, not a class. When you inject Provider<String> Spring says, "Hmm, I don't see any bean definition for the Provider interface, is there another way I can satisfy this dependency?" And Spring's answer is, "Yes, I can create an instance of org.springframework.beans.support.DefaultListableBeanFactory$DependencyProvider, but only if I know how to create T, i.e. there is a bean definition for T."
Your sample code should work if you added a configuration class to define a bean of type String:
#Configuration
public class MyConfiguration
{
#Bean
public String getMessage()
{
return "Hello!";
}
}
But if you are asking why Spring isn't injecting an instance of your MessageProvider class I suspect the problem is that it's not properly defined. You could add a qualifier to the MessageProvider definition and usage
#Component("MyMessageProvider")
public class MessageProvider implements Provider<String> {
...
and
#Inject
GreetingService(#Qualifier("MyMessageProvider") Provider<String> provider) {
...
to say exactly which Provider implementation you want injected.
Related
In my Config I define two beans of the same class that differ in the value of an enum:
#Bean
public MyClass myClassNew() {
return new MyClass(Source.NEW);
}
#Bean
public MyClass myClassOld() {
return new MyClass(Source.OLD);
}
The Class looks like this:
#Component
#RequiredArgsConstructor
public class MyClass {
private final Source source; // Source is an enum
}
When I autowire a bean in a test:
public class MyClassTest {
#Autowired
private MyClass myClassNew;
}
Spring gives me the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '...AClass$Source' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
This is totally weird. Why does Spring trying to find a bean of an enum?
I have two #Configuration classes. I need a bean from one configuration class to another. I have autowired the configuration 1 into 2. All works fine. When executing the unit testing, am getting the below exception.
setUpContext(com.trafigura.titan.framework.services.messaging.loader.SpringLoadTest)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.xxx.MessagingServicesConfig': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.EMSJMSConfig com.xxx.MessagingServicesConfig.emsJmsConfig;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type[com.xxx.EMSJMSConfig] 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)}
Is there anything I need to do additionally to make this working?
Below is the setup for testing.
#Configuration
#Import({MessagingServicesConfig.class,...,EMSJMSConfig.class
})
public class MessagingConfig {}
#Profile("EMS-MESSAGING")
#Configuration
public class EMSJMSConfig {
#Bean
public javax.jms.ConnectionFactory jmsSubscriberConnectionFactory() throws JMSException {
SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory(tibjmsConnectionFactory());
return singleConnectionFactory;
}
}
#Configuration
public class MessagingServicesConfig {
#Autowired
private EMSJMSConfig emsJmsConfig;
#Bean(destroyMethod = "shutdown")
public MessagingService messagingService() throws JMSException {
...
ConnectionFactory cf=emsJmsConfig.jmsSubscriberConnectionFactory(); // Getting NPE at this line.
}
}
and finally the test class,
public class MessagingServicesConfigTest {
private MessagingServicesConfig config;
private EMSJMSConfig emsJmsConfig;
#BeforeMethod
public void setUp() throws Exception {
config = new MessagingServicesConfig();
... //what needs to be done here to have the EMSJMSConfig
}
#Test
public void testBuildsCorrectService() throws JMSException {
MessagingService service = config.messagingService();
...
}
}
By calling new you're creating object yourself, Spring doesn't know anything about it.
Moreover, you should have a test configuration which will be aware of your beans.
Use an appropriate Runner to load SpringContext.
#ContextConfiguration(classes = TestConfig.class)
#RunWith(SpringRunner.class)
class Tests {
#Autowired // if needed
private MessagingServicesConfig config;
}
While in TestConfig you can create beans or import configuration from the Application:
#Configuration
#Import({MessagingServicesConfig.class})
public class TestConfig {}
#Configuration
#Import({EMSJMSConfig.class})
public class MessagingServicesConfig {}
Or you can refer to your config classes directly:
#ContextConfiguration(classes = {MessagingServicesConfig.class, EMSJMSConfig.class})
This question already has an answer here:
What is a NoSuchBeanDefinitionException and how do I fix it?
(1 answer)
Closed 6 years ago.
I stack with above mentioned exception and really don't understate why it is appeared. I am using spring boot and declare bean through the annotation.
Application is executed by this class:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
My problem bean has the following declaration:
#Service
public class OrderSvc extends AbstractService implements DAOService {
I try to put it in the following bean:
#RestController
public class OrderController {
#Autowired
CarSvc carSvc;
#Autowired
OrderSvc orderSvc;
and the exception is appeared: Could not autowire field: biz.Services.OrderSvc biz.controllers.rest.administrator.OrderController.orderSvc; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [biz.Services.OrderSvc] 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)}
I have also CarSvc bean that is located at the same package as OrderSvc and extends the same classes but there are no problems with it injection
#Service
public class CarSvc extends AbstractService implements DAOService<Car> {
Do you have any ideas why this exception appears ?
Spring creates proxies for classes that declare #Transactional, so that it is able to add the transactional behaviour and intercepted calls to your object. If the bean extends any interface Spring is going to create a Dynamic Proxy using the JDK Reflection API and this can only be done by interface. The proxy is a new object implementing the same interface. So your target bean is not your implementation but a proxy. That is why you were getting a non qualify bean exception.
CGLIB, on the other hand, can create a proxy by subclassing.
So, to get it working, you need to change your bean type to the interface or you can configure cglib using #EnableTransactionManagement(proxyTargetClass = true).
Try to to autowire your beans using interfaces rather than implementations :
#RestController
public class OrderController {
#Autowired
#Qualifier("carSvc")
DAOService carSvc;
#Autowired
#Qualifier("orderSvc")
DAOService orderSvc;
}
Edit : But before that you have to give names to your services :
#Service("carSvc")
public class CarSvc extends AbstractService implements DAOService<Car> {}
#Service("orderSvc")
public class OrderSvc extends AbstractService implements DAOService<Order> {}
What's going on here is that Spring generate proxies of your services based on the CarSvc, OrderSvc and implement the DAOService but does not extend the CarSvc, OrderSvc.
//somthing like this
class CarSvcProxy implement DAOService {
public Object getOrder(Long id) {
try {
// ...
txManager.commit();
} catch (Exception ex) {
txManager.rollback();
}
}
}
#RestController
public class OrderController {
//So when you do this :
#Autowired
CarSvc carSvc;
//it's somehow like if you did :
CarSvc carSvc = new CarSvcProxy(); //carSvc != CarSvcProxy
//But this will work :
DAOService carSvc = new CarSvcProxy(); //because CarSvcProxy implement DAOService
}
I found the code which leads to exception but I really don't undestand why.
In my OrderSvc there is the following method:
#Transactional(readOnly = true)
public Object getOrder(Long id) {
final Order order = getDAO().findOne(id);
OrderDTO orderDTO = modelMapper.map(order, OrderDTO.class);
return orderDTO;
}
So if the annotation #Transactional(readOnly = true) was excluded the application can be excecuted without problem... Do you have any ideas why this annotation lead to NoSuchBeanDefinitionException ?
I created an interface and a class:
public interface UserService {
List<User> listAll();
}
#Transactional
public class DefaultUserService implements UserService {
private String tableName;
public List<User> listAll() { someDao.listAllFromTable(tableName); }
public void setTableName(String tableName) { this.tableName = tableName; }
}
Also in my application context xml file context.xml, I defined:
<bean id="userService" class="mypackage.DefaultUserService">
<property name="tableName" value="myusers" />
</bean>
Then I want to test the DefaultUserService:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:context-test.xml"})
#TransactionConfiguration(transactionManager = "testTransactionManager")
#Transactional
public class UserServiceTest {
#Autowired
private DefaultUserService userService;
#Before
public void setup() {
userService.setTableName("mytesttable");
}
#Test
public void test() {
// test with userService;
userService.listAll();
}
}
Notice it uses context-test.xml, which imported the original context.xml:
<import resource="classpath:context.xml"/>
Unfortunately, when the test starts, spring throws exception:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'mypackage.UserServiceTest':
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field:
private mypackage.DefaultUserService mypackage.userService
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [mypackage.DefaultUserService] 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)}
I'm not sure where is wrong, why spring can't find the bean DefaultUserService I defined?
It's because #Transactional places the bean is behind a jdk proxy implementing UserService interface, after that the bean is only available as UserService and not DefaultUserService.
See https://stackoverflow.com/a/18875681/241986.
You can try setting the table name with a property placeholder #Value("${someprop}") and define that property in test context, or create another interface that will expose setTableName(), and autowire that helper interface into the test case.
I'm not sure there are any easy solutions of the problem, I think this task can be subsumed under the problem of bean redefinition in Spring test-context framework
Spring beans redefinition in unit test environment
Try to replace the class DefaultUserService to the interface UserService
public class UserServiceTest {
#Autowired
private UserService userService;
....
}
You have not defined the getter for your property tableName in your implementing class.Spring IOC container works on the POJO model
I have a standard bean with some properties that need to be autowired.
#Service
public class MyServiceImpl implements MyService {
#Autowired
private FirstRepository first;
public MyServiceImpl() {
}
I use a Java Config to find the beans:
#Configuration
#ComponentScan(basePackages = "com.company", excludeFilters = { #Filter(Configuration.class) })
public class MainConfig {
}
However, the FirstRepository Bean doesn't exist so I create it in a BeanFactoryPostProcessor:
public class RepoGeneratorPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition jpaR = new GenericBeanDefinition();
jpaR.setBeanClass(JpaRepositoryFactoryBean.class);
jpaR.setAutowireCandidate(true);
jpaR.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
jpaR.setLazyInit(false);
jpaR.setPropertyValues(new MutablePropertyValues().add("repositoryInterface", FirstRepository.class));
RootBeanDefinition definition = new RootBeanDefinition();
definition.setBeanClass(FirstRepository.class);
definition.setAutowireCandidate(true);
definition.setFactoryBeanName("&jpaR");
definition.setFactoryMethodName("getObject");
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_NAME);
definition.setLazyInit(false);
definition.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
registry.registerBeanDefinition("jpaR", jpaR);
registry.registerBeanDefinition("first", definition);
}
When I start my application I get the following exception which seems to suggest that Spring can't find the FirstRepository bean.
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.FirstRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
If I remove the #Autowired annotation I can see after start up that the FirstRepository bean is properly created.
Any suggestions?
This exception is saying that there is no bean defined for the FirstRepository class when the project is being built. Which I cannot see it here either.
The simplest solution would be to have a bean definition in your application-context.xml like this:
<bean id="firstRepository" class="your.package.FirstRepository" autowire="byName"/>
In this case, at the start up, there will be that bean definition.
I don't think you need the & before the beanname in
definition.setFactoryBeanName("&jpaR");
I used something like that in my project
definition.setFactoryBeanName("jpaR");
and it worked as expected
The & is needed if you need to get the factory bean of the bean named first.
&first should return jpaR.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-extension-factorybean