Affects: 6.1.0
It worked before 6.1.0 release
Steps to reproduce
- Create two service classes implementing same interface
public interface SomeService {
}
@Service
public class SomeServiceFirst implements SomeService {
}
@Service
public class SomeServiceSecond implements SomeService {
}
- Try to inject one of service by constructor parameter name as qualifier:
@Component
public class DemoApplication {
private final SomeService someServiceSecond;
public DemoApplication(SomeService someServiceSecond) {
this.someServiceSecond = someServiceSecond;
}
public static void main(String[] args) {
new AnnotationConfigApplicationContext(DemoApplication.class.getPackageName());
}
}
- There is exception as result:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoApplication' defined in file [...\demo\target\classes\com\example\demo\DemoApplication.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.example.demo.SomeService' available: expected single matching bean but found 2: someServiceFirst,someServiceSecond
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:802)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:241)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1193)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:105)
at com.example.demo.DemoApplication.main(DemoApplication.java:17)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.SomeService' available: expected single matching bean but found 2: someServiceFirst,someServiceSecond
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:218)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1418)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
... 14 more
Comment From: sbrannen
Hi @Ilia-poliakov,
Congratulations on submitting your first issue for the Spring Framework! 👍
I unfortunately cannot reproduce that behavior locally against main
.
For example, the following all-in-one test class passes for me.
package demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
@SpringJUnitConfig
class FallbackQualifierTests {
@Test
void test(@Autowired DemoApplication demoApplication) {
assertThat(demoApplication.someServiceSecond).isInstanceOf(SomeServiceSecond.class);
}
@Configuration
@ComponentScan
static class Config {
}
interface SomeService {
}
@Service("someServiceFirst")
static class SomeServiceFirst implements SomeService {
}
@Service("someServiceSecond")
static class SomeServiceSecond implements SomeService {
}
@Service
static class DemoApplication {
final SomeService someServiceSecond;
DemoApplication(SomeService someServiceSecond) {
this.someServiceSecond = someServiceSecond;
}
}
}
In addition, I copied your examples verbatim to a local example
package and modified the main()
method as follows.
public static void main(String[] args) {
try (var context = new AnnotationConfigApplicationContext(DemoApplication.class.getPackageName())) {
DemoApplication application = context.getBean(DemoApplication.class);
System.err.println("SomeService: " + application.someServiceSecond);
}
}
That outputs:
SomeService: example.SomeServiceSecond@6179e425
If you would like us to investigate this further, please provide a minimal, complete sample application that we can download and run ourselves -- for example, a public Git repository or a ZIP file attached to this issue.
Thanks
Comment From: snicoll
It worked before 6.1.0 release
Make sure that you compile your code with -parameters
, see the second paragraph of this section of the upgrade notes. And you should have seen a warning in the logs stating as much with 6.0.x
.
Comment From: Ilia-poliakov
Thank you for your response! It works when I compile code with -parameters
like @snicoll advised. I think this issue could be closed due this is not a bug.