Affects: 6.1.0

It worked before 6.1.0 release

Steps to reproduce

  1. Create two service classes implementing same interface
public interface SomeService {
}

@Service
public class SomeServiceFirst implements SomeService {
}

@Service
public class SomeServiceSecond implements SomeService {
}
  1. 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());
    }
}

  1. 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.