spring-projects / spring-projects/spring-framework

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

Open
#18,751 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: core type: enhancement
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

Description

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:

  • #18750 Inconsistency between property Injection and setter Injection causes NoUniqueBeanDefinitionException
  • #18854 Clarify @Bean(autowire=NO)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing ConfigurationClassPostProcessor and AutowiredAnnotationBeanPostProcessor for the MyParentBean example, then inspect InjectionMetadata.InjectedElement#checkPropertySkipping. Determine whether configuration-time setter or field injection should be recognized as already satisfied, and define completion as preventing the duplicate injection and resulting NoUniqueBeanDefinitionException.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.