2

I'm trying to upgrade a SpringBoot application from version 2.0.5-RELEASE to 2.1.2-RELEASE and I encounter a weird exception with a @Query annotation in a JpaRepository.
This query was correct with release 2.0.5 but throws an IllegalArgumentException: Already found parameter binding with same index / parameter name but differing binding type! on startup with release 2.1.2.

I wrote a sample project to reproduce this exception Sample project.

Here is the sample @Query annotation:

@RestResource
@Query(value = "select i from Parent i " +
    "where (?#{principal.userId} = 1 or ?#{principal.userId} = 2) " +
    "and i.name like %:text% " +
    "and i.name not like '%foobarfoobar%' " +
    "and i.application.title like %:text%")
Page<Parent> findByText(@Param("text") String text,  Pageable pageable);

I find it weird because if I change a little the query as below (I only put the part with ?#{principal…} to the end of the query), the application starts with no exception:

@RestResource
@Query(value = "select i from Parent i " +
    "where i.name like %:text% " +
    "and i.name not like '%foobarfoobar%' " +
    "and i.application.title like %:text% and " +
    "(?#{principal.userId} = 1 or ?#{principal.userId} = 2) ")
Page<Parent> findByText(@Param("text") String text,  Pageable pageable);

Note: don't pay attention to the meaning of the query, it's only a technical sample to reproduce the exception on startup.

Here is the full stacktrace:

lang.IllegalArgumentException: Already found parameter binding with same index / parameter name but differing binding type! Already have: LikeBinding [name: text, position: null, type: LIKE (1): [IsLike, Like]], found LikeBinding [name: text, position: null, type: CONTAINING (1): [IsContaining, Containing, Contains]]! If you bind a parameter multiple times make sure they use the same binding.
at org.springframework.util.Assert.isTrue(Assert.java:118) ~[spring-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.StringQuery$ParameterBindingParser.lambda$checkAndRegister$5(StringQuery.java:387) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:1.8.0_181]
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[na:1.8.0_181]
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382) ~[na:1.8.0_181]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_181]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_181]
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:1.8.0_181]
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:1.8.0_181]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_181]
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[na:1.8.0_181]
at org.springframework.data.jpa.repository.query.StringQuery$ParameterBindingParser.checkAndRegister(StringQuery.java:387) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.StringQuery$ParameterBindingParser.parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(StringQuery.java:294) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.StringQuery$ParameterBindingParser.access$000(StringQuery.java:182) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.StringQuery.<init>(StringQuery.java:73) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.DeclaredQuery.of(DeclaredQuery.java:38) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.StringQuery.deriveCountQuery(StringQuery.java:110) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.AbstractStringBasedJpaQuery.<init>(AbstractStringBasedJpaQuery.java:68) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:61) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:76) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:56) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:139) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:206) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:79) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lookupQuery(RepositoryFactorySupport.java:566) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$mapMethodsToQuery$1(RepositoryFactorySupport.java:559) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_181]
at java.util.Iterator.forEachRemaining(Iterator.java:116) ~[na:1.8.0_181]
at java.util.Collections$UnmodifiableCollection$1.forEachRemaining(Collections.java:1049) ~[na:1.8.0_181]
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[na:1.8.0_181]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_181]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_181]
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_181]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_181]
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_181]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.mapMethodsToQuery(RepositoryFactorySupport.java:561) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$new$0(RepositoryFactorySupport.java:551) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at java.util.Optional.map(Optional.java:215) ~[na:1.8.0_181]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:551) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:324) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:297) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.util.Lazy.getNullable(Lazy.java:211) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.util.Lazy.get(Lazy.java:94) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:300) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:119) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1741) ~[spring-beans-5.1.4.RELEASE.jar:5.1.4.RELEASE]
... 102 common frames omitted
  • Did you check the real SQL this query is creating? – André Pacheco Feb 11 '19 at 13:01
  • I updated the project to have a unit test and a trace of the SQL query on the custom endpoint `/parents/search/findByText`. The test pass on release 2.0.5 and fails on release 2.1.2 with the exception `IllegalArgumentException: Already found parameter binding with same name / parameter` – François Clément Feb 13 '19 at 14:30
  • I got a similar problem in the updating and what worked to me was exclude the dependencies and run everything again. – André Pacheco Feb 13 '19 at 14:46
  • Similar situation [here](https://stackoverflow.com/questions/55495377/spring-boot-2-query-named-parameter-binding-value-resolution-messes-up-after-up) does anyone have an idea about how this LikeBinding resolution happens? It seems to happen only when SPEL is used – grog Apr 05 '19 at 15:21
  • @grog: I didn't find an explanation for this bug, but I found a workaround for my own real query (not the one I wrote in the sample project) by changing the order of my `where` statements… Really weird! – François Clément Apr 08 '19 at 07:14

0 Answers0