[
https://issues.apache.org/jira/browse/OPENJPA-2785?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16814571#comment-16814571
]
Mark Struberg commented on OPENJPA-2785:
----------------------------------------
Cool, thanks for reporting this bug and for providing feedback!
> 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)