Description
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:
- Introspect factory method return type for type variable resolution at injection points [SPR-11521] #16146 Introspect factory method return type for type variable resolution at injection points
1 votes, 3 watchers