[ 
https://issues.apache.org/jira/browse/OPENJPA-2785?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Mark Struberg resolved OPENJPA-2785.
------------------------------------
       Resolution: Fixed
         Assignee: Mark Struberg
    Fix Version/s: 3.1.0

Thanks for the report!
I've just comitted a fix for this issue.
Can you please give it a try and report back if it works or not? txs!


> Queries invoked by Spring data that have parameters fail
> --------------------------------------------------------
>
>                 Key: OPENJPA-2785
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-2785
>             Project: OpenJPA
>          Issue Type: Bug
>          Components: criteria
>    Affects Versions: 3.1.0
>            Reporter: Michael Wiles
>            Assignee: Mark Struberg
>            Priority: Major
>             Fix For: 3.1.0
>
>
> When you invoke a query provided/built by spring data when it contains a 
> parameter this fails.
> Only affects version 3.1.0
>  
> See [https://github.com/michaelwiles/openjpa-spring-data-bug] for demo 
> project.
> Here is the stack trace:
> org.springframework.dao.InvalidDataAccessApiUsageException: Cannot execute 
> query; declared parameters "ParameterExpression<String>" were not given 
> values. You must supply a value for each of the following parameters, in the 
> given order: [ParameterExpression<String>]; nested exception is 
> <openjpa-3.1.0-re2160a11145bd3b2a03d61a8752fb52febcec4cc nonfatal user error> 
> org.apache.openjpa.persistence.ArgumentException: Cannot execute query; 
> declared parameters "ParameterExpression<String>" were not given values. You 
> must supply a value for each of the following parameters, in the given order: 
> [ParameterExpression<String>]
>  at 
> org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:373)
>  at 
> org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:127)
>  at 
> org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
>  at 
> org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
>  at 
> org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
>  at 
> org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
>  at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>  at 
> org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138)
>  at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>  at 
> org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
>  at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>  at 
> org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
>  at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>  at 
> org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
>  at com.sun.proxy.$Proxy64.findByName(Unknown Source)
>  at 
> com.afrozaar.bug.openjpa.OpenjpaSpringDataJpaApplicationTests.MemberByName(OpenjpaSpringDataJpaApplicationTests.java:30)
>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>  at 
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>  at 
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>  at java.lang.reflect.Method.invoke(Method.java:498)
>  at 
> org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
>  at 
> org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
>  at 
> org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
>  at 
> org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
>  at 
> org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
>  at 
> org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
>  at 
> org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
>  at 
> org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
>  at 
> org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
>  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
>  at 
> org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
>  at 
> org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
>  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
>  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
>  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
>  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
>  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
>  at 
> org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
>  at 
> org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
>  at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
>  at 
> org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
>  at 
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
>  at 
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
>  at 
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
>  at 
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
>  at 
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
>  at 
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
>  Caused by: <openjpa-3.1.0-re2160a11145bd3b2a03d61a8752fb52febcec4cc nonfatal 
> user error> org.apache.openjpa.persistence.ArgumentException: Cannot execute 
> query; declared parameters "ParameterExpression<String>" were not given 
> values. You must supply a value for each of the following parameters, in the 
> given order: [ParameterExpression<String>]
>  at org.apache.openjpa.kernel.QueryImpl.assertParameters(QueryImpl.java:1849)
>  at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:905)
>  at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:843)
>  at 
> org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:601)
>  at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:297)
>  at org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:314)
>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>  at 
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>  at 
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>  at java.lang.reflect.Method.invoke(Method.java:498)
>  at 
> org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:402)
>  at com.sun.proxy.$Proxy77.getResultList(Unknown Source)
>  at 
> org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:129)
>  at 
> org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91)
>  at 
> org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136)
>  at 
> org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125)
>  at 
> org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
>  at 
> org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
>  at 
> org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
>  at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>  at 
> org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
>  at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>  at 
> org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
>  at 
> org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
>  at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>  at 
> org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
>  ... 41 more
>  And some of my comments (originally from a reply to the mailing list:)
> I can't upgrade the 3.1 until this issue is fixed as basically, as far as I 
> can tell, any parameterised call via spring data does not work.
>   
>  Not sure it's the right place to discuss this but the way I see it the 
> ParameterExpressionImpl 
> ([https://github.com/apache/openjpa/blob/master/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java])
>  has acquired a hashCode and equals with this release - 
> [https://github.com/apache/openjpa/commit/0e4ec5b392b978c4515b26c60e485f2b610de94f#diff-e357856846fb8b88f15c08e60891cc35]
>  and this is the code of the problem with spring data.
>   
>  Now what's happening is that the compile is called - and this is called 
> before the parameter expression has a value. All hashcode calcs are done and 
> stuff is added to a set.
>   
>  Then later on the value for the parameter is set. This causes changes to the 
> hashCode and equals, resulting in the problem that I'm seeing.
>   
>  Now I apologise if I'm completely out of line but I'm wondering why the 
> value is included in the hashCode and equals of a Parameter as surely a value 
> is a "runtime" concept and it not necessarily available at compile time.
>   
>  Now the hashCode and equals were added for good reason I assume, and 
> furthermore, the value is included in the hashCode/equals also for good 
> reason. But we arguably need a mechanism to view the parameter purely from a 
> metadata point of view (which is I think what we need here) as well as from a 
> metadata+value point of view.
>   
>  But I do wonder why the ParamterExpressionImpl does include the value in the 
> hashCode and equals. My gut feel is that it's not necessary.
>   
>  Relevant stack traces: first time hashCode is called - at this point the 
> value is not specified in the ParameterExpressionImpl. Notice that the 
> CriteriaQueryImpl.compile kicks this off.
>   
>  
> org.apache.openjpa.persistence.criteria.ParameterExpressionImpl<T>.hashCode() 
> line: 154
>  java.util.HashMap<K,V>.hash(java.lang.Object) line: 338
>  
> java.util.LinkedHashMap<K,V>(java.util.HashMap<K,V>).containsKey(java.lang.Object)
>  line: 595
>  org.apache.openjpa.lib.util.OrderedMap<K,V>.containsKey(java.lang.Object) 
> line: 70
>  
> org.apache.openjpa.persistence.criteria.CriteriaQueryImpl<T>.registerParameter(org.apache.openjpa.persistence.criteria.ParameterExpressionImpl<?>)
>  line: 227
>  
> org.apache.openjpa.persistence.criteria.CriteriaExpressionVisitor$ParameterVisitor.enter(org.apache.openjpa.persistence.criteria.CriteriaExpression)
>  line: 106
>  
> org.apache.openjpa.persistence.criteria.Expressions.acceptVisit(org.apache.openjpa.persistence.criteria.CriteriaExpressionVisitor,
>  org.apache.openjpa.persistence.criteria.CriteriaExpression, 
> javax.persistence.criteria.Expression<?>...) line: 106
>  
> org.apache.openjpa.persistence.criteria.ParameterExpressionImpl<T>(org.apache.openjpa.persistence.criteria.SelectionImpl<X>).acceptVisit(org.apache.openjpa.persistence.criteria.CriteriaExpressionVisitor)
>  line: 156
>  
> org.apache.openjpa.persistence.criteria.Expressions.visitChildren(org.apache.openjpa.persistence.criteria.CriteriaExpressionVisitor,
>  javax.persistence.criteria.Expression<?>...) line: 121
>  
> org.apache.openjpa.persistence.criteria.Expressions.acceptVisit(org.apache.openjpa.persistence.criteria.CriteriaExpressionVisitor,
>  org.apache.openjpa.persistence.criteria.CriteriaExpression, 
> javax.persistence.criteria.Expression<?>...) line: 108
>  
> org.apache.openjpa.persistence.criteria.Expressions$Equal(org.apache.openjpa.persistence.criteria.Expressions$BinaryLogicalExpression).acceptVisit(org.apache.openjpa.persistence.criteria.CriteriaExpressionVisitor)
>  line: 278
>  
> org.apache.openjpa.persistence.criteria.CriteriaQueryImpl<T>.collectParameters(org.apache.openjpa.persistence.criteria.CriteriaExpressionVisitor)
>  line: 681
>  *org.apache.openjpa.persistence.criteria.CriteriaQueryImpl<T>.compile() 
> line: 672* 
>  
> org.apache.openjpa.persistence.EntityManagerImpl.createQuery(javax.persistence.criteria.CriteriaQuery<T>)
>  line: 1898
>   
>  Then the error I get, occurs here - in org.apache.openjpa.kernel.QueryImpl
>   
>    protected void assertParameters(StoreQuery q, StoreQuery.Executor ex, Map 
> params) {
>          if (!q.requiresParameterDeclarations())
>              return;
>   
>          OrderedMap<Object,Class<?>> paramTypes = 
> ex.getOrderedParameterTypes(q);
>          *for (Object actual : params.keySet()) {*
>              *if (!paramTypes.containsKey(actual))*
>              throw new UserException(_loc.get("unbound-params",
>                  actual, paramTypes.keySet()));
>          }
>          for (Object expected : paramTypes.keySet())
> {             if (!params.containsKey(expected))             throw new 
> UserException(_loc.get("unbound-params",                 expected, 
> paramTypes.keySet()));         }
>  
>          for (Entry<Object, Class<?>> entry : paramTypes.entrySet())
> {             if (entry.getValue().isPrimitive()                 && 
> params.get(entry.getKey()) == null)                 throw new 
> UserException(_loc.get("null-primitive-param", entry.getKey()));         }
>     }
>   
>  The error occurs in the bold stuff.
>   
>  And the fundamental reason as far as I can tell is that the paramtypes map 
> was populated when the value was set and then the *actual* reference in this 
> code has the value set...
>   
>  Iow, getOrderedParameterTypes returns the map created before the value was 
> set and the params.keySet has parameterExpressionImpls that have their values 
> set.
>   
>  And you know what happens when you use a hashMap and you change the hashCode 
> after you've populated the hashmap.
>   
>  Error stack trace:
>  at org.apache.openjpa.kernel.QueryImpl.assertParameters(QueryImpl.java:1849)
>  at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:905)
>  at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:843)
>  at 
> org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:601)
>  at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:297)
>  at org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:314)
>  at 
> org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.java:343)
>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>  at 
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>  at 
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>  at java.lang.reflect.Method.invoke(Method.java:498)
>  at org.springframework.orm.jpa.SharedEntityManagerCreat



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to