Roger Suen
Roger Suen

Reputation: 51

NoSuchBeanDefinitionException when injecting javax.inject.Provider<T> to constructors using Spring

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: {}

Upvotes: 1

Views: 1451

Answers (1)

HairOfTheDog
HairOfTheDog

Reputation: 2737

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.

Upvotes: 0

Related Questions