spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.6k stars 38.13k forks source link

Spring 4.2.6 autowiring generics problem: org.springframework.beans.factory.BeanCreationException: Could not autowire field [SPR-14398] #18970

Closed spring-projects-issues closed 5 years ago

spring-projects-issues commented 8 years ago

Ted Kin opened SPR-14398 and commented

Problem background

I am migrating from Spring 3 to Spring 4 and everything worked fine on Spring 3 so something must have been changed in Spring 4 in the autowiring interfaces with generics.. I am attaching simple sample application reproducing the problem.

The exception

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'firstService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private my.package.SecondService my.package.FirstServiceImpl.secondService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [my.package.SecondService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=secondService)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) 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:772) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) at org.apache.cxf.transport.servlet.CXFServlet.createSpringContext(CXFServlet.java:151) at org.apache.cxf.transport.servlet.CXFServlet.loadBus(CXFServlet.java:74) at org.apache.cxf.transport.servlet.CXFNonSpringServlet.init(CXFNonSpringServlet.java:77)

Classes

@Component("firstService")
    public class FirstServiceImpl extends BaseService implements FirstService {
        @Autowired
        @Qualifier("secondService")
        private SecondService<Shoes, ShoesPayableThingForm> secondService;

    }

    public interface SecondService<T extends PayableThing,S extends PayableThingForm<?>> {

    }

    @Component("secondService")
    public class SecondServiceImpl extends BaseService implements SecondService<PayableThing,PayableThingForm<PayableThing>> {

    }

    public class Shoes implements PayableThingWithDiscount{

    }

    public interface PayableThingWithDiscount extends PayableThing{

    }

    public class ShoesPayableThingForm implements PayableThingForm<Shoes>{

    }

    public interface PayableThingForm<T extends PayableThing> {

    }

    public interface PayableThing {
    }

After Spring debugging...

During autowiring Spring 4.2.6 Class ResolvableType returns false from method where it seems it should return true (I think so.. because SecondServiceImpl is not autowired due to this check)

private boolean isAssignableFrom(ResolvableType other, Map<Type, Type> matchedBefore) {}}

here:

if (exactMatch ? !ourResolved.equals(otherResolved) : !ClassUtils.isAssignable(ourResolved, otherResolved)) {
            return false;
        }

with this parameters catched on debug:

this = {ResolvableType@23689} "my.package.Shoes" other = {ResolvableType@23691} "my.package.PayableThing" matchedBefore = {IdentityHashMap@23692} size = 1 ourBounds = null typeBounds = null exactMatch = true checkGenerics = true ourResolved = {Class@23346} "class my.package.Shoes" otherResolved = {Class@23544} "interface my.package.PayableThing"}}

To reproduce that error

In case u would be so kind to reproduce this error, it is enough to run this junit:

@Configuration
@ComponentScan(value="my.package")
public class MyApplicationTest {

    private AnnotationConfigApplicationContext context = null;

    @Before
    public void setUp() throws Exception {
        context = new AnnotationConfigApplicationContext(MyApplicationTest.class);
    }

    @After
    public void tearDown() throws Exception {
        context.close();
    }

    @Test
    public void test() {

        //FirstService firstService = context.getBean(FirstService.class);
    }

Affects: 4.2.6

Attachments:

3 votes, 3 watchers

spring-projects-issues commented 5 years ago

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.