See spring-projects-experimental/spring-native#1022 for background.
While working on spring-native, we've found a behavior that might be a bug in the core container support for the functional registration of beans (through instance suppliers).
Some of our samples are failing with org.springframework.beans.factory.NoSuchBeanDefinitionException
. The missing bean is of type PluginRegistry<T,S>
and is contributed through a PluginRegistryFactoryBean<T,S>
(with T
and S
being concrete types: 'org.springframework.plugin.core.PluginRegistry
While debugging the issue, we've found that the current code generation process in spring-native contributes that definition to the context with:
BeanDefinitionRegistrar.of("relProviderPluginRegistry", ResolvableType.forClassWithGenerics(PluginRegistryFactoryBean.class, LinkRelationProvider.class, LinkRelationProvider.LookupContext.class)).withFactoryMethod(HateoasConfiguration.class, "relProviderPluginRegistry")
.instanceSupplier(() -> context.getBean(HateoasConfiguration.class).relProviderPluginRegistry()).register(context);
The important part is that we're declaring the PluginRegistryFactoryBean
type as the ResolvableType
target type in the definition; this seems to confuse the core container in the org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
and especially the org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
sequence. Instead of considering the generic type of the bean produced by the FactoryBean
and if it's assignable to the required type for the injection point, this seems to only consider the provided target type.
This might be linked with the fact that we're heavily using the instanceSupplier
mechanism instead of factory methods.
We've validated that providing the type produced by the Factory directly as the target ResolvableType
(so 'PluginRegistry
We need to consider this case and know whether this behavior is expected or if this shows a problem with the current suport of instance suppliers.
Comment From: bclozel
Closing in favor of spring-projects-experimental/spring-native#1030
Comment From: snicoll
Discussing this topic further, we'd still like to experiment how we can check the FactoryBean
type in GenericTypeAwareAutowireCandidateResolver
.
Comment From: snicoll
The following bean definition fails to inject the plugin registry:
BeanDefinitionRegistrar.of("relProviderPluginRegistry", ResolvableType.forClassWithGenerics(PluginRegistryFactoryBean.class, LinkRelationProvider.class, LinkRelationProvider.LookupContext.class)).withFactoryMethod(HateoasConfiguration.class, "relProviderPluginRegistry")
.instanceSupplier(() -> context.getBean(HateoasConfiguration.class).relProviderPluginRegistry()).register(context);
If we move the target type to the actual type produced by the BeanFactory
, injection is successful:
BeanDefinitionRegistrar.of("relProviderPluginRegistry", ResolvableType.forClassWithGenerics(PluginRegistry.class, LinkRelationProvider.class, LinkRelationProvider.LookupContext.class)).withFactoryMethod(HateoasConfiguration.class, "relProviderPluginRegistry")
.instanceSupplier(() -> context.getBean(HateoasConfiguration.class).relProviderPluginRegistry()).register(context);
Comment From: jhoeller
As far as I can tell, this is effectively a duplicate of #29385 where we determine the nested generic from a FactoryBean target type. And as of the recent revision in #32489 and in particular #32590, I see no such cases left uncovered anymore.