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

MockitoPostProcessor can trigger early initialization of factory beans #20665

Closed
antoniomacri opened this issue Mar 24, 2020 · 5 comments
Closed
Assignees
Labels
type: bug A general bug
Milestone

Comments

@antoniomacri
Copy link

antoniomacri commented Mar 24, 2020

I'm working on a SpringBoot project which also uses Spring Data Gemfire, so I'm posting here hoping it is the correct place.

In a SpringBootTest when I use MockBean with a cache-config.xml containing scope="global", I get the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'prog': Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.apache.geode.cache.Scope' for property 'scope'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.apache.geode.cache.Scope' for property 'scope': no matching editors or conversion strategy found

Spring Data Gemfire should register the ScopeConverter (in CustomEditorBeanFactoryPostProcessor) which matches case-insensitive the xml value with the Scope enum. This actually happens when running the application. But not (correctly) in tests using MockBean.

Full reproducer:
https://github.com/antoniomacri/spring-boot-sdg-mockbean

Complete stacktrace:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'prog': Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.apache.geode.cache.Scope' for property 'scope'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.apache.geode.cache.Scope' for property 'scope': no matching editors or conversion strategy found
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:828)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.apache.geode.cache.Scope' for property 'scope'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.apache.geode.cache.Scope' for property 'scope': no matching editors or conversion strategy found
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:590)
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:604)
	at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:219)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1723)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1679)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1426)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
	... 38 more
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.apache.geode.cache.Scope' for property 'scope': no matching editors or conversion strategy found
	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:262)
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:585)
	... 44 more

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 24, 2020
@mbhave
Copy link
Contributor

mbhave commented Mar 26, 2020

This seems to be happening because MockitoPostProcessor runs before CustomEditorBeanFactoryPostProcessor. When MockitoPostProcessor tries to get the existing beans, AbstractAutowireCapableBeanFactory creates an instance and puts in the factoryBeanInstanceCache. At this time the bean instance that is created does not have the custom property editors because CustomEditorBeanFactoryPostProcessor has not post processed the bean factory yet.

The test passes if the name of the bean that should be replaced by a mock is specified as follows:

@MockBean(name="progRepository")

@antoniomacri
Copy link
Author

It works, great!

...But why? It's not clear to me.

Thanks

@mbhave mbhave added the for: team-attention An issue we'd like other members of the team to review label Mar 26, 2020
@philwebb philwebb added type: bug A general bug and removed for: team-attention An issue we'd like other members of the team to review status: waiting-for-triage An issue we've not yet triaged labels Mar 26, 2020
@philwebb philwebb added this to the 2.2.x milestone Mar 26, 2020
@wilkinsona
Copy link
Member

We think we may be able to fix this by prohibiting eager init when getting bean names by type.

@mbhave mbhave self-assigned this Apr 21, 2020
@mbhave
Copy link
Contributor

mbhave commented Apr 21, 2020

@wilkinsona @philwebb The only way I could think of to test this was by registering a factory bean definition. That seems to trigger early initialization. Could one of you take a look?

@wilkinsona
Copy link
Member

That looks good to me. The only alternative that I can think of is to try and mimic Spring Data GemFire's registration of a custom editor and a failure because it's not registered in time due to eager init. That's almost certainly going to be more hoops to jump through with no difference in coverage.

@mbhave mbhave changed the title MockBean: no matching editors or conversion strategy found MockitoPostProcessor can trigger early initialization of factory beans Apr 22, 2020
@mbhave mbhave modified the milestones: 2.2.x, 2.2.7 Apr 22, 2020
@mbhave mbhave closed this as completed in b9c2b7b Apr 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants