I am trying to autowire bean with generic type (for expample IService) in other service with bounded generic type (DependingServiceNotWorking). This resulted in throwing NoSuchBeanDefinitionException. For legacy issues in project where I found this issue, autowiring of DependingServiceNotWorking bean is manual by beanFactory.autowireBean(..).

Please see following repositories for reproduction: https://github.com/paloliska/autowiring-bug https://github.com/paloliska/autowiring-bug-boot

Affects: spring-boot 2.4.3, spring-core 5.2.9.RELEASE

Comment From: drgnchan

@paloliska hi! as you can see,the type of DependingServiceNotWorking's dependency iService is sk.liska.autowiringbug.service.IService<sk.liska.autowiringbug.data.DataParent> which is resolve by the code below.

DependencyDescriptor.java:

public ResolvableType getResolvableType() {
        ResolvableType resolvableType = this.resolvableType;
        if (resolvableType == null) {
            resolvableType = (this.field != null ?
                    ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
                    ResolvableType.forMethodParameter(obtainMethodParameter()));
            this.resolvableType = resolvableType;
        }
        return resolvableType;
    }

But the generic type of your bean iServiceImpl is DataChild.so GenericTypeAwareAutowireCandidateResolver.checkGenericTypeMatch() will return false.if serviceImpl.method() can do your job with DataParent only, in my opinion,you are supposed to ignore the generic type when implement IService.


@Service
public class ServiceImpl implements IService {

    @Override
    public void method(DataParent arg) {
        System.out.println(arg.toString());
    }
}

after that,the application will be started successfully.

Comment From: paloliska

Hi as iService is bounded generic, I would expect that this will resolve the dependency successfully: GenericTypeAwareAutowireCandidateResolver:117 (in method checkGenericTypeMatch()):

// Fallback: no BeanFactory set, or no type resolvable through it
// -> best-effort match against the target class if applicable.
if (targetType == null && rbd != null && rbd.hasBeanClass() && rbd.getFactoryMethodName() == null) {
    Class<?> beanClass = rbd.getBeanClass();
    if (!FactoryBean.class.isAssignableFrom(beanClass)) {
        targetType = ResolvableType.forClass(ClassUtils.getUserClass(beanClass));  
    }
}

Comment From: snicoll

@paloliska you have described the difference between the two use cases quite well. In the first case, the generic is part of the class signature and the container can access its definition at runtime. In the second case, the DataChild generic in DependingServiceNotWorking<DataChild> is not available at runtime, a classical case of type erasure.

There's nothing we can do about that as the type is not available at runtime.

Comment From: paloliska

Hi, If I define new DependingServiceNotWorking(), generic is defined at runtime, or am I missing something?

At last, could you please advice me, if there is any workaround? Something like @Qualifier, which will force spring to autowire in this particular case.

Thank you

Comment From: snicoll

If I define new DependingServiceNotWorking(), generic is defined at runtime, or am I missing something?

No, it is defined at compile time, like the one that's working but the difference is that information is not retained in the bytecode. What I mean by runtime is when the application runs and the ApplicationContext reads the type information to figure out what to do.

It's hard to provide a workaround based on a simplified sample (thank you for sharing that by the way!). It could be that those shouldn't be beans or that the generic information could be moved elsewhere. For follow-up questions, please ask on StackOverflow, as mentioned in the guidelines for contributing, we prefer to use the issue tracker only for bugs and enhancements.