Issue Details (XML | Word | Printable)

Key: NUCRDBMS-645
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Unassigned
Reporter: Rp
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
DataNucleus Store RDBMS

NPE in UpdateRequest when using optimistic txns, new-table inheritance, version in a field and updating field in subclass

Created: 08/Feb/13 09:36 PM   Updated: 20/Feb/13 12:05 PM   Resolved: 14/Feb/13 03:12 PM
Component/s: ORM
Affects Version/s: 2.2.4, 3.0.10, 3.1.4, 3.2.0.m3
Fix Version/s: 3.2.0.m4

File Attachments: 1. Zip Archive 645.zip (34 kB)
2. Zip Archive dn-bug-proof.zip (4 kB)

Environment:
* Linux-3.2.0
* openjdk-7-jdk
* datanucleus-core, datanucleus-rdbms, datanucleus-api-jpa
* GWT, with RequestFactoryServlet
* Spring 3.1.2.RELEASE
* PostgreSQL 9.1

Forum Thread URL: http://www.datanucleus.org/servlet/forum/viewthread_thread,7370
Datastore: PostgreSQL
Severity: Production


 Description  « Hide
Trying to update a field from an entity that inherits from an abstract entity causes NPE

[INFO] 19:29:39 ERROR [btpool0-2][CustomRequestFactoryServlet$ApplicationExceptionLogger] Server Error
[INFO] java.lang.NullPointerException: null
[INFO] at org.datanucleus.store.rdbms.request.UpdateRequest.execute(UpdateRequest.java:368) ~[datanucleus-rdbms-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.updateTable(RDBMSPersistenceHandler.java:411) ~[datanucleus-rdbms-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.updateTable(RDBMSPersistenceHandler.java:407) ~[datanucleus-rdbms-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.updateObject(RDBMSPersistenceHandler.java:384) ~[datanucleus-rdbms-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.state.JDOStateManager.flush(JDOStateManager.java:3723) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.ExecutionContextImpl.flushInternalWithOrdering(ExecutionContextImpl.java:3929) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.ExecutionContextImpl.flushInternal(ExecutionContextImpl.java:3852) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.ExecutionContextImpl.flush(ExecutionContextImpl.java:3794) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.ExecutionContextImpl.preCommit(ExecutionContextImpl.java:4182) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.ExecutionContextImpl.transactionPreCommit(ExecutionContextImpl.java:427) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:397) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:286) ~[datanucleus-core-3.2.0-m1.jar:na]
[INFO] at org.datanucleus.api.jpa.JPAEntityTransaction.commit(JPAEntityTransaction.java:103) ~[datanucleus-api-jpa-3.2.0-m1.jar:na]
[INFO] at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]

Sort Order: Ascending order - Click to sort in descending order
Rp added a comment - 08/Feb/13 09:38 PM
I attached the entities. Run the code from "Main".

nicolas added a comment - 10/Feb/13 04:18 PM
I do not think this is a valid use of JPA.
Retrieval by navigation from detached objects is not supported, so only persistent fields that have been loaded before detachment should be used. Changes to detached entity objects are not stored in the database unless modified detached objects.

See JPA spec, section 3.2.7 Detached Entities: "Detached entity instances continue to live outside of the persistence context in which they were persisted or retrieved. Their state is no longer guaranteed to be synchronized with the database state.
[..]
If the persistent field or property is an association, the available state of an associated instance may only
be safely accessed if the associated instance is available. The available instances include:
• Any entity instance retrieved using find().
• Any entity instances retrieved using a query or explicitly requested in a fetch join.
• Any entity instance for which an instance variable holding non-primary-key persistent state
was accessed by the application."

In other words, the entity must be merged (em.merge()) back first. Also, the @Version needs to be added on D. Then it works.

Without the @Version though there is a problem:
Feb 10, 2013 4:16:43 PM org.datanucleus.store.rdbms.request.UpdateRequest execute
SEVERE: Object "D@e1baffa" (id="2") has been changed in the datastore since your last read. Your transaction is using version "1" but this doesnt exist in the datastore now
Feb 10, 2013 4:16:43 PM Main main
INFO: >> Exception thrown retrieving objects
javax.persistence.RollbackException: Transaction failed to commit
at org.datanucleus.api.jpa.JPAEntityTransaction.commit(JPAEntityTransaction.java:122)
at Main.main(Main.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: javax.persistence.OptimisticLockException: Some instances failed to flush successfully due to optimistic verification problems.
at org.datanucleus.api.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:421)
at org.datanucleus.api.jpa.JPAEntityTransaction.commit(JPAEntityTransaction.java:116)
... 6 more
Caused by: org.datanucleus.exceptions.NucleusOptimisticException: Object "D@e1baffa" (id="2") has been changed in the datastore since your last read. Your transaction is using version "1" but this doesnt exist in the datastore now
at org.datanucleus.store.rdbms.request.UpdateRequest.execute(UpdateRequest.java:385)
at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.updateTable(RDBMSPersistenceHandler.java:412)
at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.updateTable(RDBMSPersistenceHandler.java:408)
at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.updateObject(RDBMSPersistenceHandler.java:385)
at org.datanucleus.state.JDOStateManager.flush(JDOStateManager.java:3729)
at org.datanucleus.ExecutionContextImpl.flushInternalWithOrdering(ExecutionContextImpl.java:4019)
at org.datanucleus.ExecutionContextImpl.flushInternal(ExecutionContextImpl.java:3942)
at org.datanucleus.ExecutionContextImpl.flush(ExecutionContextImpl.java:3876)
at org.datanucleus.ExecutionContextImpl.preCommit(ExecutionContextImpl.java:4272)
at org.datanucleus.ExecutionContextImpl.transactionPreCommit(ExecutionContextImpl.java:581)
at org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:404)
at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:293)
at org.datanucleus.api.jpa.JPAEntityTransaction.commit(JPAEntityTransaction.java:103)
... 6 more



Made a simpler zip to reproduce the problem with a pom file.

mvn clean
mvn compile
run Main

nicolas added a comment - 10/Feb/13 04:18 PM
simplified package.

Andy Jefferson added a comment - 14/Feb/13 03:12 PM - edited
SVN trunk works.

PS, there is no need for em.persist() or em.merge(). Objects from a query (in an extended context, or within a transaction) are in managed state. Modifying a managed object means it is then in "persistent-dirty" state and all changed go to the datastore. Obviously other JPA implementations may require that you call em.merge since they can't detect changes as easily, but then that's their problem.