spring-data-mongodb icon indicating copy to clipboard operation
spring-data-mongodb copied to clipboard

Missing native-image reflection hint for org.springframework.data.mongodb.core.aggregation.AggregationOperation

Open anguzo opened this issue 1 year ago • 8 comments

Environment

  • Spring Boot Starter Parent 3.2.2
  • Spring Security 6.2.2-SNAPSHOT (6.2.1 has error related to issue)
  • Spring Data Bom 2023.1.3-SNAPSHOT (2023.1.2 has error related to issue)
  • BellSoft Liberica NIK 21.0.2

Problem

I was exploring Spring Native capabilities on a project created using this settings in Spring Initializr. Got an error:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'healthContributorRegistry': Unsatisfied dependency expressed through method 'healthContributorRegistry' parameter 2: Error creating bean wit
h name 'mongoHealthContributor': Unsatisfied dependency expressed through method 'mongoHealthContributor' parameter 0: Error creating bean with name 'mongoTemplate': Type org.springframework.data.mongodb.core.aggregation.AggregationOpera
tion not present
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveAutowiredArgument(BeanInstanceSupplier.java:344) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:264) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:204) ~[na:na]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:949) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1216) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[demo.exe:6.1.3]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:959) ~[demo.exe:6.1.3]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624) ~[demo.exe:6.1.3]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[demo.exe:3.2.2]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[demo.exe:3.2.2]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[demo.exe:3.2.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[demo.exe:3.2.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[demo.exe:3.2.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[demo.exe:3.2.2]
        at com.example.demo.DemoApplication.main(DemoApplication.java:10) ~[demo.exe:na]
        at [email protected]/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH) ~[na:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mongoHealthContributor': Unsatisfied dependency expressed through method 'mongoHealthContributor' parameter 0: Error creating bea
n with name 'mongoTemplate': Type org.springframework.data.mongodb.core.aggregation.AggregationOperation not present
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveAutowiredArgument(BeanInstanceSupplier.java:344) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:264) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:204) ~[na:na]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:949) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1216) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1689) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1653) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanMap(DefaultListableBeanFactory.java:1575) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1514) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1392) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:907) ~[na:na]
        at org.springframework.beans.factory.support.RegisteredBean.resolveAutowiredArgument(RegisteredBean.java:229) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveAutowiredArgument(BeanInstanceSupplier.java:341) ~[na:na]
        ... 22 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoTemplate': Type org.springframework.data.mongodb.core.aggregation.AggregationOperation not present
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:606) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1689) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1653) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanMap(DefaultListableBeanFactory.java:1575) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1514) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1392) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:907) ~[na:na]
        at org.springframework.beans.factory.support.RegisteredBean.resolveAutowiredArgument(RegisteredBean.java:229) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveAutowiredArgument(BeanInstanceSupplier.java:341) ~[na:na]
        ... 43 common frames omitted
Caused by: java.lang.TypeNotPresentException: Type org.springframework.data.mongodb.core.aggregation.AggregationOperation not present
        at [email protected]/sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:117) ~[na:na]
        at [email protected]/sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125) ~[na:na]
        at [email protected]/sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49) ~[na:na]
        at [email protected]/sun.reflect.generics.visitor.Reifier.visitArrayTypeSignature(Reifier.java:159) ~[na:na]
        at [email protected]/sun.reflect.generics.tree.ArrayTypeSignature.accept(ArrayTypeSignature.java:42) ~[na:na]
        at [email protected]/sun.reflect.generics.repository.ConstructorRepository.computeParameterTypes(ConstructorRepository.java:111) ~[demo.exe:na]
        at [email protected]/sun.reflect.generics.repository.ConstructorRepository.getParameterTypes(ConstructorRepository.java:87) ~[demo.exe:na]
        at [email protected]/java.lang.reflect.Executable.getGenericParameterTypes(Executable.java:313) ~[demo.exe:na]
        at [email protected]/java.lang.reflect.Method.getGenericParameterTypes(Method.java:337) ~[demo.exe:na]
        at org.springframework.core.BridgeMethodResolver.isResolvedTypeMatch(BridgeMethodResolver.java:178) ~[na:na]
        at org.springframework.core.BridgeMethodResolver.isBridgeMethodFor(BridgeMethodResolver.java:168) ~[na:na]
        at org.springframework.core.BridgeMethodResolver.searchCandidates(BridgeMethodResolver.java:147) ~[na:na]
        at org.springframework.core.BridgeMethodResolver.resolveBridgeMethod(BridgeMethodResolver.java:109) ~[na:na]
        at org.springframework.core.BridgeMethodResolver.getMostSpecificMethod(BridgeMethodResolver.java:90) ~[na:na]
        at org.springframework.aop.support.AopUtils.getMostSpecificMethod(AopUtils.java:206) ~[na:na]
        at org.springframework.aop.aspectj.AspectJExpressionPointcut.getTargetShadowMatch(AspectJExpressionPointcut.java:427) ~[na:na]
        at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:291) ~[na:na]
        at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:258) ~[na:na]
        at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:295) ~[na:na]
        at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:327) ~[na:na]
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128) ~[demo.exe:6.1.3]
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97) ~[demo.exe:6.1.3]
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78) ~[demo.exe:6.1.3]
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:366) ~[demo.exe:6.1.3]
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:318) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:437) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1776) ~[demo.exe:6.1.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[demo.exe:6.1.3]
        ... 58 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.data.mongodb.core.aggregation.AggregationOperation
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:122) ~[na:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:86) ~[na:na]
        at [email protected]/java.lang.Class.forName(DynamicHub.java:1356) ~[demo.exe:na]
        at [email protected]/java.lang.Class.forName(DynamicHub.java:1345) ~[demo.exe:na]
        at [email protected]/sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114) ~[na:na]
        ... 85 common frames omitted
        ```

anguzo avatar Feb 13 '24 22:02 anguzo

If you'd like us to spend some time investigating, please take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.

christophstrobl avatar Feb 14 '24 06:02 christophstrobl

Sure, here is a minimal example. If I remove mongodb from dependencies then project does not throw the mentioned exception when running native executable.

demo.zip

anguzo avatar Feb 14 '24 08:02 anguzo

Thank you @anguzo for the reproducer - GraalVM decides to not include AggregationOperation in the image. However the core framework tries to inspect all methods when creating a proxy for the mongo template. This involves reading method signatures via BridgeMethodResolver and fails because of the removed AggregationOperation. @sdeleuze is there a way BridgeMethodResolver could be more lenient when resolving parameter types?

christophstrobl avatar Feb 20 '24 09:02 christophstrobl

Spring Framework is unlikely to change this code path which could introduce regressions on JVM side. I would suggest to add related hints on Spring Data side (and maybe check if other *Operation types are impacted, included outside spring-data-mongodb).

sdeleuze avatar Feb 23 '24 10:02 sdeleuze

Given the number of projects potentially having both reactive and imperative variants manually adding those hints sounds quite cumbersome and error prone. Before we do that, do we know candidates for proxy creation during the AOT phase? If so, we could hook into the processing to add missing types based on method signatures.

christophstrobl avatar Feb 23 '24 11:02 christophstrobl

@snicoll Could you please share with Christoph if that's possible (I am not sure it is)?

sdeleuze avatar Feb 27 '24 15:02 sdeleuze

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

spring-projects-issues avatar Mar 06 '24 10:03 spring-projects-issues

Sorry, I overlooked this. I'll check with Christoph.

snicoll avatar Mar 06 '24 10:03 snicoll

I'm facing the same issue with my project. Any temp solutions are fine too. @snicoll BTW is this issue not occur with previous spring boot versions ? @christophstrobl

mmuthukrishnan avatar Mar 30 '24 05:03 mmuthukrishnan

@mmuthukrishnan you can always provide additional hints yourself if needed, which may help you proceed for now.

Meanwhile I had another look at the sample project and once the org.springframework.cloud dependencies are removed things work as expected. @mmuthukrishnan are you also using spring-cloud? If so that would narrow down the component creating the proxy.

christophstrobl avatar Apr 02 '24 09:04 christophstrobl

The difference when spring-cloud-starter-openfeign is added is that it brings along spring-boot-starter-aop which adds AspectJ to the classpath. As a result, a different, AspectJ-specific, AbstractAdvisorAutoProxyCreator implementation is used and the class for which the hint is missing is being processed by one of its advisors causing the issue.

OlgaMaciaszek avatar Apr 03 '24 15:04 OlgaMaciaszek

@mmuthukrishnan you can always provide additional hints yourself if needed, which may help you proceed for now.

Meanwhile I had another look at the sample project and once the org.springframework.cloud dependencies are removed things work as expected. @mmuthukrishnan are you also using spring-cloud? If so that would narrow down the component creating the proxy.

@christophstrobl Yes I use it with spring cloud function with aws adapter.

mmarimuthu avatar Apr 03 '24 15:04 mmarimuthu

The dependency has now also been removed from spring-cloud-starter-openfeign, so after switching to Spring Cloud 2023.0.2 once it's been released, the problem won't occur with the setup from the demo.

OlgaMaciaszek avatar Apr 03 '24 16:04 OlgaMaciaszek

Thank you @OlgaMaciaszek! Closing this one.

christophstrobl avatar Apr 04 '24 06:04 christophstrobl