Affects: 4.3.x

Consider the following class heirarchy (assume constructors with @Inject for final fields):

@Component
class DataStore<R> {
    private final CachingService<R> cachingService;
}

@Component
class PersonCachingService implements CachingService<Person> {
...
}

@Component
class VehicleCachingService implements CachingService<Vehicle> {
...
}

@Component
class PeopleApp {
   private final DataStore<Person> dataStore;
}

Expected Behavior: Resolving the DataStore<Person> dependency for PeopleApp should succeed as there is only 1 matching candidate bean (personCachingService) that matches the right bounds for the type parameter of DataStore required by PeopleApp

Actual Behavior: Bean resolution fails with the following exception: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.amazon.cpcatropsplanner.CachingService<?>' available: expected single matching bean but found 2: personCachingService,vehicleCachingService

Comment From: Avinm

Update: Although at first I attributed this to type erasure, I eliminated this by testing the same with Guice. Guice is able to successfully resolve the right dependencies even for nested generics.

Comment From: Thejuampi

Hi!, I have the same problem. I have created this repo to reproduce the issue.

https://github.com/Thejuampi/possible-spring-injection-bug/tree/master/src/test/java/example/injection_bug

I hope that helps.

Comment From: lgxbslgx

At present, Spring creates beans by using the bean definition. AbstractBeanFactory.doGetBean uses getMergedLocalBeanDefinition to get the bean definition. The bean definition does not include the generic information of other beans which use it. Therefore, it can't select one bean from multiple candidates using the generic information of other beans.

@Avinm In your demo, the bean definition of DataStore doesn't include the generic information, which is named Person. When Spring creates the bean of DataStore, it can't select the right bean between PersonCachingService and VehicleCachingService.

Maybe it is great for us to record the generic information and solve this issue. It can make the program more reasonable. But it may change some basic classes which is likely to generate other issues. @sbrannen Do you have some good points?

Comment From: Avinm

@lgxbslgx : Yes, I saw this in the source when I initially planned on raising this as a PR. But hesitated because of the structural changes and seeing that there are around 200 PRs open at any given time :)

Comment From: thecooldrop

I am facing exact same issue here. Spring is not able to handle generic beans depending on other generic beans well.

Comment From: snicoll

Unfortunately, this is the expected behavior. When DataStore is created, it is created as an independent singleton bean so dependency resolution should happen. Looking at the class, it's requesting a CachingService<R> to be injected. There are literally two candidates in the context matching so the exception makes total sense.

The fact that you later one request a DataStore<Person> to be injected can't have any influence whatsoever to what the container should do when it creates the DataStore bean.