Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Starting from Spring-Boot 3.2.x the @SpyBean is not able to initialise MongoRepository bean of the generic type. #40234

Open
pavlo-reshetniak opened this issue Apr 9, 2024 · 5 comments
Labels
type: regression A regression from a previous release
Milestone

Comments

@pavlo-reshetniak
Copy link

pavlo-reshetniak commented Apr 9, 2024

Issue

Starting from Spring-Boot 3.2.x the @SpyBean is not able to initialize MongoRepository bean of the generic type.
Please check the example project: https://github.com/pavlo-reshetniak/spybean-issue-example

How to reproduce

  1. Make sure the spring-boot-starter-parent has version 3.2.x (e.g. 3.2.4) in the parent POM file
  2. Run unit test: com.example.service.ExampleServiceTest#shouldExtractDataFromMongo

Result

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.repository.ExampleRepository]: Specified class is an interface
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:77)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1311)
	... 39 more

Possible workaround

  • Downgrading the spring-boot-starter-parent to version 3.1.10 will fix the issue
  • Removing the generic type under the @SpyBean initialization will fix the issue:
From this:

   @SpyBean
   private ExampleRepository<ExampleData> exampleRepository;
   
to this:

   @SpyBean
   private ExampleRepository exampleRepository;
@wilkinsona
Copy link
Member

wilkinsona commented Apr 12, 2024

The change in behavior is due to spring-projects/spring-data-commons@98f20a4. The move away from the FactoryBean.OBJECT_TYPE_ATTRIBUTE to setting the definition's target type means that MockitoPostProcessor now fails to match the generic signature of the spied field:

Object attribute = beanDefinition.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
if (resolvableType.equals(attribute) || type.equals(attribute)) {
beans.add(beanName);
}

This failed matching means that we don't find the existing bean and instantiating one fails as it's an interface.

It's unfortunate that Framework doesn't find the factory bean when we ask for beans of a particular type:

Set<String> beans = new LinkedHashSet<>(
Arrays.asList(beanFactory.getBeanNamesForType(resolvableType, true, false)));

It doesn't find them as we are not permitting eager init so it only checks raw factory beans and not the beans created by those factory beans. Perhaps this could be improved when the bean definition has additional type information as it does in this case?

In the absence of a change in Framework, when the object type attribute's is null, I think we need to fall back to the target type information that I think we can access through getResolvableType().

@wilkinsona
Copy link
Member

I've opened spring-projects/spring-framework#32649 to track a change on the Framework side that will hopefully get this working without changing anything in Boot.

@quaff
Copy link
Contributor

quaff commented Apr 17, 2024

FYI, there are some improvements about repository definition's target type:
spring-projects/spring-data-commons@dd081d4 spring-projects/spring-data-commons@88011e6

Not sure Boot could benefit from it.

@quaff
Copy link
Contributor

quaff commented Apr 17, 2024

public interface ExampleRepository<T extends AbstractData> extends MongoRepository<ExampleData, String> {

}

I don't understand why ExampleRepository is generic? @pavlo-reshetniak

@wilkinsona
Copy link
Member

We may get something in Framework 6.2 that helps with this. Until then, we'll have to refine our own matching.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

No branches or pull requests

5 participants