spring-attic / spring-native

Spring Native is now superseded by Spring Boot 3 official native support
https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html
Apache License 2.0
2.74k stars 356 forks source link

JPA custom query throws null #660

Closed vavramovski closed 3 years ago

vavramovski commented 3 years ago

First of all, My pom.xml is generated from start.spring.io and I guess it should look fine.

As described in the title, when I use custom Query with named convention in JpaRepository, native-image throws

Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract com.example.demo.model.Cart com.example.demo.repository.CartRepository.findFirstByUserId(java.lang.Long)! null

at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.

(PartTreeJpaQuery.java:96) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:107) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:218) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:81) ~[na:na] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:100) ~[na:na] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$mapMethodsToQuery$1(QueryExecutorMethodInterceptor.java:93) ~[na:na] at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na] at java.util.Iterator.forEachRemaining(Iterator.java:133) ~[na:na] at java.util.Collections$UnmodifiableCollection$1.forEachRemaining(Collections.java:1054) ~[na:na] at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[na:na] at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na] at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na] at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na] at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na] at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:95) ~[na:na] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:85) ~[na:na] at java.util.Optional.map(Optional.java:265) ~[com.example.demo.DemoApplication:na] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.(QueryExecutorMethodInterceptor.java:85) ~[na:na] at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:303) ~[na:na] at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:323) ~[com.example.demo.DemoApplication:2.4.6] 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:329) ~[com.example.demo.DemoApplication:2.4.6] at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:144) ~[com.example.demo.DemoApplication:2.4.6] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[na:na] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[na:na] ... 45 common frames omitted Caused by: java.lang.NullPointerException: null at org.springframework.data.jpa.repository.query.QueryUtils.requiresOuterJoin(QueryUtils.java:732) ~[na:na] at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:637) ~[na:na] at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:616) ~[na:na] at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:612) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryCreator$PredicateBuilder.getTypedPath(JpaQueryCreator.java:385) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryCreator$PredicateBuilder.build(JpaQueryCreator.java:308) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryCreator.toPredicate(JpaQueryCreator.java:211) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryCreator.create(JpaQueryCreator.java:124) ~[na:na] at org.springframework.data.jpa.repository.query.JpaQueryCreator.create(JpaQueryCreator.java:59) ~[na:na] at org.springframework.data.repository.query.parser.AbstractQueryCreator.createCriteria(AbstractQueryCreator.java:119) ~[na:na] at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:95) ~[na:na] at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:81) ~[na:na] at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.(PartTreeJpaQuery.java:217) ~[na:na] at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$CountQueryPreparer.(PartTreeJpaQuery.java:348) ~[na:na] at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.(PartTreeJpaQuery.java:91) ~[na:na] ... 71 common frames omitted

The code is :

public interface CartRepository extends JpaRepository<Cart, Long> {
    Cart findFirstByUserId(Long userId);
}
DOESN'T WORK šŸ‘Ž 

BUT, if I create the query manually with @Query, it works fine.

public interface CartRepository extends JpaRepository<Cart, Long> {

    @Query("select c Cart c where c.user.id = $1")
    Cart findFirstByUserId(Long userId);

}
WORKS šŸ‘ 

The code works fine in debug environment, but fails in native-image.

On top of my mind is that this may be a RuntimeReflection error if the method is not registered automatically.

Do you guys have any suggestions or fixes about this error?

sdeleuze commented 3 years ago

It looks like we may have to refine our support to work when @Query is not used and add this use case to at least one of our JPA samples. Maybe we missed that because other methods were adding the required reflection entries in more complex sample like petclinic-jpa.

Any thoughts @schauder ?

schauder commented 3 years ago

I tried to reproduce the issue based on samples/data-jpa but failed.

@vavramovski please provide a reproducer.

schauder commented 3 years ago

Hold the horses. The issue happens when there is a reference involved. I'm able to reproduce it.