Skip to content

Should @Configuration mark @Inject fields and setters as satisfied (injected)? [SPR-14180] #18751

@spring-projects-issues

Description

@spring-projects-issues
Collaborator

Christian Hersevoort opened SPR-14180 and commented

Somewhat related to my other issue: #18750 (It's a different way to solve the same problem)

The case is as follows:

Beans:

  • MyParentBean
  • MyChildBeanA implements MyChildBean
  • MyChildBeanB implements MyChildBean
@Configuration
public class MyBeanConfiguration
{
	@Bean
	public MyParentBean myParentBean(MyChildBeanA childBeanA)
	{
		MyParentBean myParentBean = new MyParentBean();
		myParentBean.setMyChild(childBeanA);
		return myParentBean;
	}
}

@Component
public class MyParentBean
{
	private MyChildBean myChild;

	@Inject
	public void setMyChild(MyChildBean myChild)
	{
		this.myChild = myChild;
	}
}

I expect the MyParentBean.myChild field to only be Injected by the @Configuration, and not by both ConfigurationClassPostProcessor and the AutowiredAnnotationBeanPostProcessor.

Expected:

  1. ConfigurationClassPostProcessor calls MyBeanConfiguration
  2. MyParentBean is created and field/property myChild is set.
  3. myChild is marked as satisfied(Injected)

What happens:

  1. ConfigurationClassPostProcessor calls MyBeanConfiguration
  2. MyParentBean is created and field/property myChild is set.
  3. AutowiredAnnotationBeanPostProcessor tries to Inject myChild again, but fails and throws a NoUniqueBeanDefinitionException

Changing between field and property injection doesn't help either e.g:

@Component
public class MyParentBean
{
	@Inject
	private MyChildBean myChild;
}

Changing @Bean to @Bean(autowire = Autowire.NO) doesn't help either, e.g:

@Configuration
public class MyBeanConfiguration
{
	@Bean(autowire = Autowire.NO)
	public MyParentBean myParentBean(MyChildBeanA childBeanA)
	{
		MyParentBean myParentBean = new MyParentBean();
		myParentBean.setMyChild(childBeanA);
		return myParentBean;
	}
}

Is this expected behavior? I expect org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#checkPropertySkipping to be true and skip injection.

If this is expected behavior: is there a way to prevent @Bean to be injected again by the AutowiredAnnotationBeanPostProcessor?


Issue Links:

Activity

spring-projects-issues

spring-projects-issues commented on Apr 15, 2016

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

This would be great to have... if we could technically do it. Unfortunately, the body of a factory method is a black box to the framework; we have no idea what's being called there. For that reason, this currently doesn't work. I'd love to make that work though!

spring-projects-issues

spring-projects-issues commented on Apr 15, 2016

@spring-projects-issues
CollaboratorAuthor

Christian Hersevoort commented

Thanks for your quick reply!

Does this also mean @Bean(autowire = Autowire.NO) is broken? Because (even) without solving the "black-box" issue of @Configuration, the user can tell Spring the bean is "done" injecting with Autowire.NO.

Or does Autowire.NO mean something else in Spring?

spring-projects-issues

spring-projects-issues commented on Apr 15, 2016

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

This "autowire mode" indicates convention-based autowiring, introspecting setter method signatures and autowiring them by name or by type. Unfortunately, this is completely independent from annotation-driven autowiring. Autowire.NO is actually the default on @Bean, indicating no such convention-based autowiring to be performed. That said, I like the idea of a flag which allows for skipping annotation-driven injection. We could introduce a dedicated flag for that or simply repurpose Autowire.NO as you implied.

Note that these problems do not arise with constructor injection. Our general recommendation for @Bean methods interacting with annotated component classes is to favor constructor injection, with annotated constructors naturally ignored on instances returned from @Bean methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @spring-projects-issues

        Issue actions

          Should @Configuration mark @Inject fields and setters as satisfied (injected)? [SPR-14180] · Issue #18751 · spring-projects/spring-framework