@SpykBean on Spring Data Repository doesn't work anymore with JDK16+
See original GitHub issueHi,
I already stumbled over @jnizet commit https://github.com/Ninja-Squad/springmockk/commit/b6dbc1b50d4cacf72c50119fdfc5273ae5fc4677
But in our case @SpykBean isn’t working with following configuration:
- openjdk version “16.0.1” 2021-04-20
- Kotlin 1.5.21
- Spring Boot 2.5.3
- SpringMockk 3.0.1
Simple data repository spy:
@SpykBean
private lateinit var documentRepository: DocumentRepository
Exception when running the test:
...
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'documentRepository': Post-processing of FactoryBean's singleton object failed; nested exception is java.lang.IllegalAccessException: class io.mockk.impl.InternalPlatform$copyFields$1 cannot access a member of class java.lang.reflect.Proxy (in module java.base) with modifiers "protected"
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:123)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
... 68 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'documentRepository': Post-processing of FactoryBean's singleton object failed; nested exception is java.lang.IllegalAccessException: class io.mockk.impl.InternalPlatform$copyFields$1 cannot access a member of class java.lang.reflect.Proxy (in module java.base) with modifiers "protected"
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:119)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1884)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1266)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:345)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
... 87 common frames omitted
Caused by: java.lang.IllegalAccessException: class io.mockk.impl.InternalPlatform$copyFields$1 cannot access a member of class java.lang.reflect.Proxy (in module java.base) with modifiers "protected"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:385)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:687)
at java.base/java.lang.reflect.Field.checkAccess(Field.java:1096)
at java.base/java.lang.reflect.Field.get(Field.java:417)
at io.mockk.impl.InternalPlatform$copyFields$1.invoke(InternalPlatform.kt:110)
at io.mockk.impl.InternalPlatform$copyFields$1.invoke(InternalPlatform.kt:114)
at io.mockk.impl.InternalPlatform.copyFields(InternalPlatform.kt:117)
at io.mockk.impl.instantiation.AbstractMockFactory.spyk(AbstractMockFactory.kt:107)
at com.ninjasquad.springmockk.SpykDefinition.createSpy(SpykDefinition.kt:75)
at com.ninjasquad.springmockk.MockkPostProcessor.createSpyIfNecessary(MockkPostProcessor.kt:335)
at com.ninjasquad.springmockk.MockkPostProcessor$SpyPostProcessor.postProcessAfterInitialization(MockkPostProcessor.kt:398)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:437)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1929)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)
... 96 common frames omitted
The workaround is to switch to JDK <= 15.
Has anyone an idea to fix the issue?
Issue Analytics
- State:
- Created 2 years ago
- Comments:8 (3 by maintainers)
Top Results From Across the Web
@SpyBean does not work when used to spy on a Spring Data ...
Version: Spring Boot 1.4.1 Subject: @SpyBean on Data Jpa Repository bean isn't working Exception thrown: UnsatisfiedDependencyException: ...
Read more >Mockito cannot create Spy of @Autowired Spring-Data ...
@SpyBean now works with spring data repositories since spring boot ... var yourSpy = Mockito.mock(FooRepository.class, AdditionalAnswers.
Read more >Spring Boot Reference Documentation
Try the How-to documents. They provide solutions to the most common questions. Learn the Spring basics. Spring Boot builds on many other Spring...
Read more >Spring Boot and Java 16 Records - Ashish Choudhary
I have a working Spring Boot application that I will use to demo Java records with it.
Read more >Using Spring Boot @SpyBean - Shekhar Gulati
The reason test threw NullPointerException is that Spring uses MongoTemplate internally to provide implementation of your repository interfaces.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
@jnizet I agree that this is almost certainly a mockk issue with proxy spies.
Another piece of information - for whatever reason the final exception masks the original exception:
So it appears the new Java 17 strong encapsulation is what is actually breaking this. In 9-11 this just gave a warning, now it fails hard.
@ajgassner @PavelPolyakov a workaround is to add the
--add-opensJVM flag to your test execution. In Gradle (build.gradle.kts):Adding this for me causes my spied repositories to work just as before. My JVM:
Also met this issue while trying to update to JDK17.
Are there any options to overcome this? I thought common to spy on repositories. I’m surprised that not that many people report that they have this problem. I don’t see any relevant issue on mockk side.
One option I see is not to spy on the repositories 😉 But it’s said nowhere in the documentation, that one shall not do that.