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

Missing hint issue when defining a custom MongoTemplate.

Open omercelikceng opened this issue 1 year ago • 4 comments

Hello,

I have a Spring Boot service where I save data to different databases at runtime. Additionally, I need to customize some settings based on certain conditions. Therefore, I create custom MongoTemplate beans. My implementation works successfully. So, under normal conditions, I can save my data to different databases and my code works.

However, when I build my project as a native image, it throws an error during startup. For now, I have solved the problem by adding the relevant class as a hint in my project. However, I wanted to contribute by opening a pull request for this issue.

To help you reproduce the issue, I am sharing a POC project. If you follow the steps in the README.md file on the main branch, you will encounter the error. Additionally, you can switch to the solution branch to see if the solution works.

Spring Boot Version : 3.3.2

The branch link where you can reproduce the error : https://github.com/omercelikceng/native-poc-mongodb-error/tree/main The branch link where the error is resolved : https://github.com/omercelikceng/native-poc-mongodb-error/tree/solution

Error :

2024-08-07T12:48:07.223Z  WARN 1 --- [           main] o.s.c.support.GenericApplicationContext  : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'basicCrudOperation': Unsatisfied dependency expressed through field 'mongoTemplate': Error creating bean with name 'liveMongoTemplate': Type org.springframework.data.mongodb.core.aggregation.AggregationOperation not present
Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'basicCrudOperation': Unsatisfied dependency expressed through field 'mongoTemplate': Error creating bean with name 'liveMongoTemplate': Type org.springframework.data.mongodb.core.aggregation.AggregationOperation not present
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:194)
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveAndSet(AutowiredFieldValueResolver.java:167)
        at org.example.graalvm.mongodb.BasicCrudOperation__Autowiring.apply(BasicCrudOperation__Autowiring.java:17)
        at org.springframework.beans.factory.support.InstanceSupplier$1.get(InstanceSupplier.java:83)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:949)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1237)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1180)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
        at org.example.graalvm.mongodb.GraalVMMongoErrorApplication.main(GraalVMMongoErrorApplication.java:10)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liveMongoTemplate': Type org.springframework.data.mongodb.core.aggregation.AggregationOperation not present
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:607)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1443)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353)
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:188)
        ... 21 more
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)
        at [email protected]/sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125)
        at [email protected]/sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
        at [email protected]/sun.reflect.generics.visitor.Reifier.visitArrayTypeSignature(Reifier.java:159)
        at [email protected]/sun.reflect.generics.tree.ArrayTypeSignature.accept(ArrayTypeSignature.java:42)
        at [email protected]/sun.reflect.generics.repository.ConstructorRepository.computeParameterTypes(ConstructorRepository.java:111)
        at [email protected]/sun.reflect.generics.repository.ConstructorRepository.getParameterTypes(ConstructorRepository.java:87)
        at [email protected]/java.lang.reflect.Executable.getGenericParameterTypes(Executable.java:298)
        at [email protected]/java.lang.reflect.Method.getGenericParameterTypes(Method.java:333)
        at org.springframework.core.BridgeMethodResolver.isResolvedTypeMatch(BridgeMethodResolver.java:190)
        at org.springframework.core.BridgeMethodResolver.isBridgeMethodFor(BridgeMethodResolver.java:180)
        at org.springframework.core.BridgeMethodResolver.searchCandidates(BridgeMethodResolver.java:159)
        at org.springframework.core.BridgeMethodResolver.resolveBridgeMethod(BridgeMethodResolver.java:121)
        at org.springframework.core.BridgeMethodResolver.getMostSpecificMethod(BridgeMethodResolver.java:98)
        at org.springframework.aop.support.AopUtils.getMostSpecificMethod(AopUtils.java:209)
        at org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.computeTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:158)
        at org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:111)
        at org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut.matches(TransactionAttributeSourcePointcut.java:56)
        at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:262)
        at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:298)
        at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:330)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:136)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:99)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:80)
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:368)
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:320)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:438)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1809)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
        ... 30 more
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:123)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:87)
        at [email protected]/java.lang.Class.forName(DynamicHub.java:1324)
        at [email protected]/java.lang.Class.forName(DynamicHub.java:1313)
        at [email protected]/sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114)
        ... 58 more

omercelikceng avatar Aug 07 '24 15:08 omercelikceng

Thank you for reaching out - this sounds very much like #4637

christophstrobl avatar Aug 09 '24 08:08 christophstrobl

Hello @christophstrobl . Yes, I have seen this issue. It was resolved by removing the spring-cloud-starter-openfeign dependency. However, my problem is different and the related issue(https://github.com/spring-projects/spring-data-mongodb/issues/4637) has been closed. Therefore, I have created a new issue.

Normally, when I create a native image and run the application, it works successfully. However, when I define MongoTemplate and TransactionTemplate beans as custom, create a native image, and run it, I get an error. This is because AggregationOperation is not registered in the hint. If you would like to reproduce the error, I have created a POC project(minimal sample).

omercelikceng avatar Aug 09 '24 09:08 omercelikceng

@omercelikceng thank you for the reproducer - the underlying issue remains the same as with #4637 being the BridgeMethodResolver trying to read signatures from types that had been removed by GraalVM.

This is not a scenario specific to MongoOperations and MongoTemplate but may occur on any type framework tries to resolve methods on. May it be to detect candidates for transactional proxies or types being proxied for any other reason. Providing hints for AggregationOperation via data-mongodb would patch this one incarnation of the issue that will for sure surface somewhere else again.

Let me \\cc @sedleuze - maybe we could rethink 4637-comment#1953799740 regarding changes in core fw to cover this scenario.

christophstrobl avatar Aug 20 '24 13:08 christophstrobl

@christophstrobl Thank you very much for your interest. I thought that manually adding this class was the right approach. However, I understood what you meant. Actually, it was discussed that @snicoll would review this situation and provide feedback. However, it seems that the feedback was not provided, or I may have missed it. (https://github.com/spring-projects/spring-data-mongodb/issues/4637#issuecomment-1980535586). However, this issue hasn't been progressed. Also, the username 'sdeleuze' was incorrectly written, so I'm tagging again. @sdeleuze

omercelikceng avatar Aug 20 '24 14:08 omercelikceng