spring-native icon indicating copy to clipboard operation
spring-native copied to clipboard

Query method on JPARepository is failing

Open estigma88 opened this issue 3 years ago • 4 comments

Spring Boot 2.6.4 Spring Native 0.11.3 Kotlin 1.6.10

I am trying to create a demo using Spring Data JPA, but I got the following error.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Optional com.example.springnativedemo.CustomerRepository.findByName(java.lang.String)! Reason: Incomplete hierarchy for class CustomerRepository, unresolved classes [org.springframework.data.jpa.repository.JpaRepository]; nested exception is java.lang.IllegalStateException: Incomplete hierarchy for class CustomerRepository, unresolved classes [org.springframework.data.jpa.repository.JpaRepository]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[na:na]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[na:na]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[na:na]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[na:na]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[na:na]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:934) ~[na:na]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[na:na]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[na:na]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[na:na]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.4]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.4]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.4]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.4]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.4]
        at com.example.springnativedemo.SpringNativeDemoApplicationKt.main(SpringNativeDemoApplication.kt:13) ~[na:na]
Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Optional com.example.springnativedemo.CustomerRepository.findByName(java.lang.String)! Reason: Incomplete hierarchy for class CustomerRepository, unresolved classes [org.springframework.data.jpa.repository.JpaRepository]; nested exception is java.lang.IllegalStateException: Incomplete hierarchy for class CustomerRepository, unresolved classes [org.springframework.data.jpa.repository.JpaRepository]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:106) ~[na:na]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$mapMethodsToQuery$1(QueryExecutorMethodInterceptor.java:94) ~[na:na]
        at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
        at java.util.Iterator.forEachRemaining(Iterator.java:133) ~[na:na]
        at java.util.Collections$UnmodifiableCollection$1.forEachRemaining(Collections.java:1061) ~[na:na]
        at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845) ~[na:na]
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
        at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
        at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:96) ~[na:na]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:86) ~[na:na]
        at java.util.Optional.map(Optional.java:260) ~[na:na]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:86) ~[na:na]
        at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:364) ~[na:na]
        at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:322) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.2]
        at org.springframework.data.util.Lazy.getNullable(Lazy.java:230) ~[na:na]
        at org.springframework.data.util.Lazy.get(Lazy.java:114) ~[na:na]
        at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:328) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.2]
        at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:144) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:2.6.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[na:na]
        ... 16 common frames omitted
Caused by: java.lang.IllegalStateException: Incomplete hierarchy for class CustomerRepository, unresolved classes [org.springframework.data.jpa.repository.JpaRepository]
        at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.RuntimeErrorReporter.reportIncompleteHierarchy(RuntimeErrorReporter.kt:26) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassTypeConstructor.computeSupertypes(DeserializedClassDescriptor.kt:228) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:77) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:76) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValueWithPostCompute.invoke(LockBasedStorageManager.java:481) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValueWithPostCompute.invoke(LockBasedStorageManager.java:512) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor.getSupertypes(AbstractTypeConstructor.kt:26) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope.getNonDeclaredVariableNames(DeserializedClassDescriptor.kt:336) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation$variableNames$2.invoke(DeserializedMemberScope.kt:262) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation$variableNames$2.invoke(DeserializedMemberScope.kt:261) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.StorageKt.getValue(storage.kt:42) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation.getVariableNames(DeserializedMemberScope.kt:261) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation.addFunctionsAndPropertiesTo(DeserializedMemberScope.kt:349) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope.computeDescriptors(DeserializedMemberScope.kt:115) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope$allDescriptors$1.invoke(DeserializedClassDescriptor.kt:257) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope$allDescriptors$1.invoke(DeserializedClassDescriptor.kt:256) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope.getContributedDescriptors(DeserializedClassDescriptor.kt:267) ~[na:na]
        at kotlin.reflect.jvm.internal.impl.resolve.scopes.ResolutionScope$DefaultImpls.getContributedDescriptors$default(ResolutionScope.kt:50) ~[na:na]
        at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.getMembers(KDeclarationContainerImpl.kt:56) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data$declaredNonStaticMembers$2.invoke(KClassImpl.kt:162) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data$declaredNonStaticMembers$2.invoke(KClassImpl.kt:162) ~[na:na]
        at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:93) ~[na:na]
        at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data.getDeclaredNonStaticMembers(KClassImpl.kt:162) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data$allNonStaticMembers$2.invoke(KClassImpl.kt:171) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data$allNonStaticMembers$2.invoke(KClassImpl.kt:171) ~[na:na]
        at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:93) ~[na:na]
        at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data.getAllNonStaticMembers(KClassImpl.kt:171) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data$allMembers$2.invoke(KClassImpl.kt:177) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data$allMembers$2.invoke(KClassImpl.kt:177) ~[na:na]
        at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:93) ~[na:na]
        at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl$Data.getAllMembers(KClassImpl.kt:177) ~[na:na]
        at kotlin.reflect.jvm.internal.KClassImpl.getMembers(KClassImpl.kt:195) ~[na:na]
        at kotlin.reflect.full.KClasses.getFunctions(KClasses.kt:89) ~[com.example.springnativedemo.SpringNativeDemoApplicationKt:1.6.10-release-923(1.6.10)]
        at kotlin.reflect.jvm.ReflectJvmMapping.getKotlinFunction(ReflectJvmMapping.kt:136) ~[na:na]
        at org.springframework.data.util.KotlinReflectionUtils.findKotlinFunction(KotlinReflectionUtils.java:95) ~[na:na]
        at org.springframework.data.util.KotlinReflectionUtils.isSuspend(KotlinReflectionUtils.java:111) ~[na:na]
        at org.springframework.data.repository.core.support.AbstractRepositoryMetadata.getReturnType(AbstractRepositoryMetadata.java:90) ~[na:na]
        at org.springframework.data.repository.core.support.DefaultRepositoryInformation.getReturnType(DefaultRepositoryInformation.java:254) ~[na:na]
        at org.springframework.data.repository.query.QueryMethod.potentiallyUnwrapReturnTypeFor(QueryMethod.java:282) ~[na:na]
        at org.springframework.data.repository.query.QueryMethod.<init>(QueryMethod.java:81) ~[na:na]
        at org.springframework.data.jpa.repository.query.JpaQueryMethod.<init>(JpaQueryMethod.java:107) ~[na:na]
        at org.springframework.data.jpa.repository.query.DefaultJpaQueryMethodFactory.build(DefaultJpaQueryMethodFactory.java:44) ~[na:na]
        at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:87) ~[na:na]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:102) ~[na:na]
        ... 38 common frames omitted

Seems like custom query methods are not supported in the CustomerRepository interface because if you remove the method, it works.

interface CustomerRepository: JpaRepository<Customer, String> {

    fun findByName(name: String): Optional<Customer>
}

You can find a demo here to reproduce the error.

estigma88 avatar Mar 17 '22 22:03 estigma88

@christophstrobl @schauder Could you please have a look to this issue?

sdeleuze avatar Mar 18 '22 08:03 sdeleuze

As discussed with @christophstrobl, seems to work with:

@TypeHint(types = [
    org.springframework.data.jpa.repository.JpaRepository::class,
    org.springframework.data.repository.PagingAndSortingRepository::class,
    org.springframework.data.repository.CrudRepository::class,
    org.springframework.data.repository.Repository::class,
    org.springframework.data.repository.query.QueryByExampleExecutor::class,
    java.util.Optional::class,
    FluentQuery::class,
    FluentQuery.FetchableFluentQuery::class
], access = [TypeAccess.QUERY_PUBLIC_METHODS])

So it seems we can add transitively the types to make Kotlin reflection happy in query mode to keep the footprint small.

sdeleuze avatar Mar 21 '22 09:03 sdeleuze

It works, just needed to add java.time.OffsetDateTime as one of my query methods use it

estigma88 avatar Mar 22 '22 19:03 estigma88

Blocked on https://github.com/oracle/graal/issues/4418.

sdeleuze avatar Mar 23 '22 07:03 sdeleuze

Spring Native is now superseded by Spring Boot 3 official native support, see the related reference documentation for more details.

As a consequence, I am closing this issue, and recommend trying your use case with latest Spring Boot 3 version. If you still experience the issue reported here, please open an issue directly on the related Spring project (Spring Framework, Data, Security, Boot, Cloud, etc.) with a reproducer.

Thanks for your contribution on the experimental Spring Native project, we hope you will enjoy the official native support introduced by Spring Boot 3.

sdeleuze avatar Jan 02 '23 11:01 sdeleuze