Damian Bułak created OPENJPA-2718:
-------------------------------------
Summary: ClassCastException during flush
Key: OPENJPA-2718
URL: https://issues.apache.org/jira/browse/OPENJPA-2718
Project: OpenJPA
Issue Type: Bug
Components: jpa, kernel
Affects Versions: 2.4.2
Reporter: Damian Bułak
Attachments: openjpa-cascading-bug.zip
Assuming I have three entities - Organization, Department and Employee and
Organization has collection of Departments and Department has collection of
employees where each association has CascadeType.ALL, when I open three
transactions within one entity manager session:
In 1st transaction a department is created and persisted
In 2nd transaction an organization is created and previously created department
is fetched from DB and added to organization departments set, then organization
is persisted
In 3rd transaction an employee is created and added to the department created
in 1st transaction, which is again as in 2nd transaction fetched from DB.
The following exception is thrown:
{code}
<openjpa-2.4.2-r422266:1777108 fatal store error>
org.apache.openjpa.persistence.RollbackException:
org.apache.openjpa.kernel.DetachedValueStateManager cannot be cast to
org.apache.openjpa.kernel.StateManagerImpl
at
org.apache.openjpa.persistence.EntityManagerImpl.commit(EntityManagerImpl.java:595)
at
CascadeTestCase.shouldEmployeeBeCascadedFromDepartment(CascadeTestCase.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:47)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at
org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at
org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at
org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
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.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at
org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at
org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at
org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at
org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: <openjpa-2.4.2-r422266:1777108 nonfatal general error>
org.apache.openjpa.persistence.PersistenceException:
org.apache.openjpa.kernel.DetachedValueStateManager cannot be cast to
org.apache.openjpa.kernel.StateManagerImpl
at
org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:2029)
at
org.apache.openjpa.kernel.LocalManagedRuntime.commit(LocalManagedRuntime.java:81)
at org.apache.openjpa.kernel.BrokerImpl.commit(BrokerImpl.java:1526)
at
org.apache.openjpa.kernel.DelegatingBroker.commit(DelegatingBroker.java:932)
at
org.apache.openjpa.persistence.EntityManagerImpl.commit(EntityManagerImpl.java:571)
... 30 more
Caused by: java.lang.ClassCastException:
org.apache.openjpa.kernel.DetachedValueStateManager cannot be cast to
org.apache.openjpa.kernel.StateManagerImpl
at
org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushAndUpdate(PreparedStatementManagerImpl.java:134)
at
org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.flushAndUpdate(BatchingPreparedStatementManagerImpl.java:79)
at
org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushInternal(PreparedStatementManagerImpl.java:100)
at
org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flush(PreparedStatementManagerImpl.java:88)
at
org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:550)
at
org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:107)
at
org.apache.openjpa.jdbc.kernel.BatchingConstraintUpdateManager.flush(BatchingConstraintUpdateManager.java:59)
at
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:104)
at
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:77)
at
org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:731)
at
org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:131)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2205)
at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2103)
at
org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:2021)
... 34 more
{code}
What I did, I debugged the OpenJPA sources and found that persisting the
organization in the second transaction triggers flush on department however the
department state manager is marked with the FLAG_PRE_FLUSHED flag but after the
whole operation the flag is still active (it should be removed in
StateManagerImpl#afterFlush(int reason) and that's why the employee object from
3rd transaction is not persisted - the first condition in
StateManagerImpl#preFlush(boolean logical, OpCallbacks call) is false.
Obviously the Employee entity should be persisted since it is added to the
collection with cascading and at the commit time flush should trigger that
operation.
It seems that the problem is very similar to
https://issues.apache.org/jira/projects/OPENJPA/issues/OPENJPA-2360 and
probably has the same root.
I attached a simple test case which reproduces the issue.
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)