Sam Brannen opened SPR-8450 and commented

Background

Autowiring a bean with an instance of itself is not something one would normally do, but there are cases where it might be useful -- for example, to route method calls through the proxy that wraps the bean. There are of course alternatives to this, such as using load-time weaving with AspectJ proxies instead of JDK dynamic proxies.

Note that self-autowiring by name via @Resource is permitted by the framework; whereas, self-autowiring by type is not permitted by the framework as can be seen in the following code snippet from DefaultListableBeanFactory's findAutowireCandidates(String, Class, DependencyDescriptor) method.

for (String candidateName : candidateNames) {
    if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
        result.put(candidateName, getBean(candidateName));
    }
}

The name of the bean (i.e., the bean that's trying to autowire itself) is beanName. That bean is in fact an autowire candidate, but the above if-condition returns false (since candidateName equals the beanName). Thus you simply cannot autowire a bean with itself by type (at least not as of Spring 3.1 M2).

Goal

Add support for self-autowiring using @Autowired on fields and methods.

Stack Overflow Discussion

This topic was brought to our attention via a discussion on Stack Overflow.


Affects: 3.0.5

Issue Links: - #21186 Self autowiring does not work for transactional beans - #19532 Self reference fallback in 4.3 is not meant to apply to collection elements - #16794 @Autowired does not work for target bean of type Collection - #18973 Define and document rules for @Autowired self-injection in case of ambiguity

18 votes, 23 watchers

Comment From: spring-projects-issues

Chris Beams commented

On review of the StackOverflow thread, I wonder whether the "workaround" approach of using @Autowired to inject the enclosing ApplicationContext and look the bean up isn't actually a better idea. It reveals the intention more clearly that the user wants the bean as managed by Spring, e.g. post-proxying, etc. It would probably never be intuitive for someone to see a FooService that uses @Autowired to inject a FooService into itself. The fact that @Resource works here is more an inadvertent bonus than it is a feature by design.

I understand that this approach complicates unit-testability somewhat, but the use cases for this (self-injection) are probably few and far between and thus a reasonable tradeoff.

Placing within the General Backlog where it can get voted up and receive further comments, but there is no immediate intention to resolve at this time.

Comment From: spring-projects-issues

Fred Clausen commented

This is a bonus to me. In my specific case, it means I don't have to mess with the default cache proxying:

@Service(value="fooService")
public JPAFooService implements FooService {

  @Resource(name="fooService") FooService fooService;  // only works if injected by name

  @Cacheable
  List<Foo> getAll() {
     return dao.getFoos();
  };

  boolean hasFoo(Foo f) {
    List<Foo> all = getAll();              // THIS WILL BYPASS THE CACHE
    List<Foo> all2 = fooService.getAll();  // THIS WILL USE THE CACHE
  }
}

Comment From: spring-projects-issues

Chris Beams commented

Hi Fred,

Your example helps make clear why this issue is probably best considered as an advertisement for AspectJ-based advice (as opposed to the proxy approach). By using load- or compile-time weaving and spring-aspect's built in AJ aspects, you can forget about this proxy business entirely.

The proxy approach hits about 80% of the use cases, and that's why we advocate it first. But cases like this are really where bytecode-weaving shines.

Comment From: spring-projects-issues

Ben Fagin commented

On the one hand, calling a method on a reference to your 'real' self could probably be described as an anti-pattern. On the other hand, any day that I can avoid bytecode weaving is a good day. The idea of using a self reference is certainly present in other languages. Used judiciously, perhaps in an application transitioning from proxying to weaving, autowiring a self reference can be helpful.

Is autowiring oneself by type safe though? Is there a risk of autowiring some other bean entirely?

Comment From: spring-projects-issues

Sam Brannen commented

Is autowiring oneself by type safe though?

No, it is potentially dangerous (see below).

Is there a risk of autowiring some other bean entirely?

Yes, autowiring by type could potentially result in a different bean of the same type being injected. That's why Fred Clausen, in his example above, explicitly references the bean by name in order to ensure that the bean gets a reference to itself (potentially proxied). He does this using the bean name/ID in conjunction with @Resource; however, the same could be achieved using qualifiers (i.e., via @Qualifier).

Comment From: spring-projects-issues

Niels Bech Nielsen commented

Given that the use case for this problem is self proxy invocation, wouldn't it be simpler to address the use case through an explicit annotation, (e.g @AutowireSelf, @AutowireProxy, or something). It would probably be easy for the BeanFactory to resolve the case correctly, and it would probably be more explanatory than both autowire-by-name and autowire-by-type.

I have found the use case a few times and keeps being amazed at how people work around the problem usually in some less than elegant way. Some by autowire of some kind or by massive delegation or using static holders. Usually the use case have been identified through a massive debugging effort, because the developer was unaware of the problem in the first place.

With a specific annotation it would be easy to document the effect in proxy annotations: "Should you wish to call a method annotated with @xxxProxyAnnotationOfSomeKind from another method in the same class, you must use a self-proxy(link to annotation)."

Comment From: spring-projects-issues

Premraj Motling commented

@Juergen Will this be supported in coming version? I liked the idea of doing this explicitly (like having special annotation @AutowireSelf)

Comment From: spring-projects-issues

Juergen Hoeller commented

For 4.2, I intend to research the options and suggest a recommended solution for this scenario... A dedicated annotation may indeed be the best compromise.

Juergen

Comment From: spring-projects-issues

Eduardo Simioni commented

I have a use case affected by this problem, where I think the solution of having a specific annotation wouldn't work, or maybe it would, but then it would have to consider collections as well, holding self and others.

In my applications there is an event mechanism, to put it very simple:

All @ServiceS extend AbstractService, with the abstract having a:

@Autowired private List\ eventListeners;

The AbstractService triggers events on some common situations in my application. A @Service can be EventListener, meaning that it can potentially be injected in itself through the eventListeners, since it extends AbstractService.

Now, naturally I'm not handling events from a service inside itself, but I need this to be implemented this way so that it is generic and duplication free.

The injection works normally, but there are some corner cases that I don't recall right now where it doesn't. If you want more details or the exact corner cases, I could investigate and provide.

Comment From: spring-projects-issues

Ben Fagin commented

I have been using a @Self annotation in my own code to handle these situations. I usually find it necessary when I want to ensure that my declarative transaction and caching semantics are preserved. In a perfect world the weaving would take care of this, but I have never been able to get that to work 100% of the time.

This is the code I use in my own projects. While not the absolute best, it has worked so far.

@Component
public class SelfWiringBeanPostProcessor implements BeanPostProcessor, SmartLifecycle, BeanFactoryAware {
    private final List<Callable<Void>> injections = new ArrayList<>();
    private BeanFactory beanFactory;
    private boolean isRunning = false;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        injections.add(() -> {

            // find all fields marked @Self
            ReflectionUtils.doWithFields(bean.getClass(),

                // get the latest bean and inject it
                field -> {
                    Object ref = beanFactory.getBean(beanName);
                    ReflectionUtils.makeAccessible(field);
                    field.set(bean, ref);
                },

                // filter by annotation
                field -> field.isAnnotationPresent(Self.class)
            );

            return null;
        });

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    // ------------------------------------------------------------------- //

    @Override
    public boolean isAutoStartup() {
        return true;
    }

    @Override
    public void stop(Runnable callback) {
        stop();
        callback.run();
    }

    @Override
    public void start() {
        for (Callable<Void> method : injections) {
            try {
                method.call();
            } catch (Exception ex) {
                throw Throwables.propagate(ex);
            }
        }

        isRunning = true;
    }

    @Override
    public void stop() {
        isRunning = false;
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }

    @Override
    public int getPhase() {
        return Integer.MIN_VALUE;
    }
}

Comment From: spring-projects-issues

Othon Crelier commented

It will be really interesting to have this solved. Particularly interested in @Async and @Transactional use cases.

Comment From: spring-projects-issues

Sam Brannen commented

FYI: this has been resolved in the following GitHub commit:

https://github.com/spring-projects/spring-framework/commit/4a0fa69ce469cae2e8c8a1a45f0b43f74a74481d

Comment From: spring-projects-issues

Peter Rader commented

Not working well in 4.3.5.RELEASE!

{{ /** * Authorithy to decide what movements are disallowed.

  • \

  • Not responsible in case of movements that are blessed in past (i.e. part of a

  • loading-process of mementos, deserialization, loading a.s.).

  • \

  • Notice that this council is only responsible for non-headless-environments. */ @Named public final class LayerDropAuthorithy extends LayerDragNDropTransferHandler implements DropVetoCouncilor { public LayerDropAuthorithy() { System.out.println(SpringVersion.getVersion());

    }
    
    /**
     * The council to decide where to drop elements.
     */
    // @Inject
    public final DropVetoCouncilor[] dropVetoCouncil = null;
    
    @Inject
    public final ApplicationContext ac = null;
    
    @Override
    public boolean allowsMove(final VectorPublishNode target, final Set<VectorPublishNode> nodesConcerned) {
        boolean blocked = false;
        for (DropVetoCouncilor dropVetoCouncilor : dropVetoCouncil) {
            blocked |= dropVetoCouncilor.blockMove(nodesConcerned, target);
        }
        return blocked;
    }
    
    @Override
    public boolean blockMove(Set<VectorPublishNode> nodesConcerned, VectorPublishNode target) {
        // Block if root-element shall be moved.
        for (VectorPublishNode vectorPublishNode : nodesConcerned) {
            if (vectorPublishNode.getParent() == null) {
                return true;
            }
        }
        return false;
    }
    
    @PostConstruct
    public void test() {
        System.out.println(SpringVersion.getVersion());
        System.out.println("dddddddddd->" + ac.getBeansOfType(DropVetoCouncilor.class).size());
    }
    

}

}}

gives: {{4.3.5.RELEASE dddddddddd->1}}

but uncomment // @Inject gives {{ Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'addSquare': Unsatisfied dependency expressed through field 'history'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyImpl': Unsatisfied dependency expressed through field 'layer'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerImpl': Unsatisfied dependency expressed through field 'dragNDropHandler'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerDropAuthorithy': Unsatisfied dependency expressed through field 'dropVetoCouncil'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.vectorpublish.desktop.vp.api.layer.dnd.DropVetoCouncilor[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject()} org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'addSquare': Unsatisfied dependency expressed through field 'history'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyImpl': Unsatisfied dependency expressed through field 'layer'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerImpl': Unsatisfied dependency expressed through field 'dragNDropHandler'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerDropAuthorithy': Unsatisfied dependency expressed through field 'dropVetoCouncil'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.vectorpublish.desktop.vp.api.layer.dnd.DropVetoCouncilor[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject()} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1225) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:552) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) at org.springframework.context.annotation.AnnotationConfigApplicationContext.\(AnnotationConfigApplicationContext.java:84) at net.vectorpublish.desktop.vp.VectorPublishApplicationContext.\(VectorPublishApplicationContext.java:18) at net.vectorpublish.desktop.vp.Startup.main(Startup.java:31) at VPTest.testMe(VPTest.java:50) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189) at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165) at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85) at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyImpl': Unsatisfied dependency expressed through field 'layer'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerImpl': Unsatisfied dependency expressed through field 'dragNDropHandler'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerDropAuthorithy': Unsatisfied dependency expressed through field 'dropVetoCouncil'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.vectorpublish.desktop.vp.api.layer.dnd.DropVetoCouncilor[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject()} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1225) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:552) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1136) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 46 more Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerImpl': Unsatisfied dependency expressed through field 'dragNDropHandler'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerDropAuthorithy': Unsatisfied dependency expressed through field 'dropVetoCouncil'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.vectorpublish.desktop.vp.api.layer.dnd.DropVetoCouncilor[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject()} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1225) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:552) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1136) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 59 more Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'layerDropAuthorithy': Unsatisfied dependency expressed through field 'dropVetoCouncil'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.vectorpublish.desktop.vp.api.layer.dnd.DropVetoCouncilor[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject()} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1225) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:552) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1136) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 72 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.vectorpublish.desktop.vp.api.layer.dnd.DropVetoCouncilor[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject()} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1474) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1102) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 85 more }}

Comment From: spring-projects-issues

Peter Rader commented

Ignore last message please, using 4.3.4.RELEASE solved the problem. Looks like a different bug.

Comment From: ankitkpd

Looks like after the fix findAutowireCandidates() will either return candidates that are not selfReferenced or candidates that are Collection/Map beans and are self referenced.

But it won't return both i.e. non self referenced candidates that are being added with

for (String candidate : candidateNames) {
    if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
        addCandidateEntry(result, candidate, descriptor, requiredType);
    }
}

AND candidates that are Collection/Map beans & are self referenced being added with the fix i.e.

for (String candidate : candidateNames) {
    if (isSelfReference(beanName, candidate) &&
            (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
            isAutowireCandidate(candidate, fallbackDescriptor)) {
        addCandidateEntry(result, candidate, descriptor, requiredType);
    }
}

Because if condition if (result.isEmpty()) would prevent it to do so.

Is there a way to get autowired candidates of both types?

Comment From: ankitkpd

@spring-projects-issues appreciate you feedback about https://github.com/spring-projects/spring-framework/issues/13096#issuecomment-2073032069 Thanks