Skip to content

Collection autowiring does not resolve field-level type variable against containing class [SPR-15160] #19726

Closed
@spring-projects-issues

Description

@spring-projects-issues

thomas weidner opened SPR-15160 and commented

Spring fails to autowire fields correctly, if the field contains a generic type variable, which is later bound. It does not matter if the type variable is bound by deriving a concrete (not generic) type or just defining a bean of the generic type with fixed type parameters.

Spring either finds not all beans or too many beans, whereas the second case is especially troublesome as it breaks static type checking.

Consider two beans of types Foo and Bar both implementing an interface Base. Moreover, we have a type BeanCollector<C> which autowires a single field of type List<C>, a field of type C and prints both values after construction. Additionally, a BaseBeanCollector<C behaves the same way, but the type variable has a type bound on Base.We define the following beans:

	@Bean
	public BeanCollector<Foo> fooBeanCollector() {
		return new BeanCollector<>("foo");
	}

	@Bean
	public BeanCollector<Bar> barBeanCollector() {
		return new BeanCollector<>("bar");
	}

	@Bean
	public BaseBeanCollector<Foo> fooBaseBeanCollector() {
		return new BaseBeanCollector<Foo>("foo base");
	}

	@Bean
	public BaseBeanCollector<Bar> barBaseBeanCollector() {
		return new BaseBeanCollector<>("bar base");
	}


	@Bean
	public BaseBeanCollector<Foo> fooBaseBeanCollectorAnonClass() {
		return new BaseBeanCollector<Foo>("foo base anonymous class") {};
	}

	@Bean
	public BaseBeanCollector<Bar> barBaseBeanCollectorAnonClass() {
		return new BaseBeanCollector<Bar>("bar base anonymous class") {};
	}


	@Bean
	public BeanCollector<Foo> fooBeanCollectorAnonClass() {
		return new BeanCollector<Foo>("foo anonymous class") {};
	}

	@Bean
	public BeanCollector<Bar> barBeanCollectorAnonClass() {
		return new BeanCollector<Bar>("bar anonymous class") {};
	}

	@Bean
	public FooBeanCollector fooBeanCollectorExtraClass() {
		return new FooBeanCollector();
	}

	@Bean
	public FooBaseBeanCollector fooBaseBeanCollectorExtraClass() {
		return new FooBaseBeanCollector();
	}

Here, Foo(Base)BeanCollector are classes which extend (Base)BeanCollector<Foo>.

The really remarkable output of this code is:

Beans for foo base: [com.example.Bar@7fb4f2a9, com.example.Foo@4dc27487]
Beans for foo: [] and org.springframework.jmx.export.annotation.AnnotationMBeanExporter@13df2a8c
Beans for bar base: [com.example.Bar@7fb4f2a9, com.example.Foo@4dc27487]
Beans for foo base anonymous class: [com.example.Foo@4dc27487]
Beans for bar base anonymous class: [com.example.Bar@7fb4f2a9]
Beans for foo anonymous class: [] and com.example.Foo@4dc27487
Beans for bar anonymous class: [] and com.example.Bar@7fb4f2a9
Beans for foo extra class: [] and com.example.Foo@4dc27487
Beans for foo base extra class: [com.example.Foo@4dc27487]
Beans for bar: [] and org.springframework.jmx.export.annotation.AnnotationMBeanExporter@13df2a8c

The following table shows the autowiring behaviour:
| | collector instance without extra Type | collector instance as anonymous type | collector instance as class type |
| no type bound | empty bean list, arbitrary single bean | empty bean list | empty bean list |
| type bound | too many beans in list | OK | OK |

Either, spring should behave as expected, or report an error that autowiring using type variables is not supported. The current behaviour can trigger all kind of subtle bugs.


Affects: 4.3.5

Reference URL: https://github.com/thomas001/spring-generic-autowire-bug

Issue Links:

1 votes, 3 watchers

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions