Issue Details (XML | Word | Printable)

Key: NUCCORE-534
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Andy Jefferson
Reporter: Karl M. Davis
Votes: 0
Watchers: 1
Operations

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

Persist of new object with compound detached object chain causes exception

Created: 15/Jan/08 09:45 PM   Updated: 11/Jun/10 01:38 PM   Resolved: 26/May/10 08:20 AM
Component/s: JDO
Affects Version/s: 1.0.0.m1, 1.0.0.m2, 1.0.0.m3, 1.0.0.m4, 1.0.0.final, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.1.0.m1, 1.1.0.m2, 1.1.0.m3, 1.1.0.m4, 1.1.0.release, 1.1.1, 1.1.2, 1.1.3, 1.1.4, 1.1.5, 1.1.6, 2.0.0.m1, 2.0.0.m2, 2.0.0.m3, 2.0.0.m4, 2.0.0.release, 2.0.1, 2.0.2, 2.0.3, 2.0.4, 2.1.0.m1, 2.1.0.m2, 2.1.0.m3
Fix Version/s: 2.1.0.release

File Attachments: 1. Zip Archive testCase-CORE-3488.zip (7 kB)

Environment: Vista, Java 1.6

Forum Thread URL: http://www.jpox.org/servlet/forum/viewthread?thread=4828
Datastore: Apache Derby
Severity: Development


 Description  « Hide
When persisting an object with a compound identity that includes a detached field that itself has a compound identity, the following error is generated:
[2008-01-11 11:42:18,354]DEBUG400718[main] - org.jpox.util.Log4JLogger.debug(Log4JLogger.java:60) -
  INSERT INTO CHILD ("NAME",PARENT_GRANDPARENT_NAME_OID_OID,PARENT_NAME_OID) VALUES (<'child1'>,<null>,<null>)
[2008-01-11 11:42:18,356] WARN400720[main] - org.jpox.util.Log4JLogger.warn(Log4JLogger.java:98) -
  [JPOX-052208] Insert of object "phmpro.detachtest.Child@1b1deea" using statement
  "INSERT INTO CHILD ("NAME",PARENT_GRANDPARENT_NAME_OID_OID,PARENT_NAME_OID) VALUES (?,?,?)"
  failed : At least one parameter to the current statement is uninitialized.
Exception in thread "main" javax.jdo.JDODataStoreException: [JPOX-052208] Insert of object
  "phmpro.detachtest.Child@1b1deea" using statement
  "INSERT INTO CHILD ("NAME",PARENT_GRANDPARENT_NAME_OID_OID,PARENT_NAME_OID) VALUES (?,?,?)"
  failed : At least one parameter to the current statement is uninitialized.
at org.jpox.jdo.JPOXJDOHelper.getJDOExceptionForJPOXException(JPOXJDOHelper.java:289)
at org.jpox.jdo.AbstractPersistenceManager.jdoMakePersistent(AbstractPersistenceManager.java:646)
at org.jpox.jdo.AbstractPersistenceManager.makePersistent(AbstractPersistenceManager.java:666)
at phmpro.detachtest.DetachmentTester.save(DetachmentTester.java:39)
at phmpro.detachtest.DetachmentTester.main(DetachmentTester.java:24)

My object hierarchy is, roughly:
Child[name, parent], Parent[name, grandparent], Grandparent[name]
Where all fields in each class are part of a compound PK with a custom ID class.

I've done some debugging, and found the following exception is thrown before that one (but doesn't get logged):
NullPointerException.<init>() line: 36 [local variables unavailable]
Parent.jdoCopyKeyFieldsFromObjectId(PersistenceCapable$ObjectIdFieldConsumer, Object) line: not available
PersistenceCapableMapping.setObjectAsValue(ObjectManager, Object, int[], Object, StateManager, int) line: 602
PersistenceCapableMapping.setObject(ObjectManager, Object, int[], Object, StateManager, int) line: 327
ParameterSetter.storeObjectField(int, Object) line: 142
JDOStateManagerImpl(AbstractStateManager).providedObjectField(PersistenceCapable, int, Object) line: 752
Child.jdoProvideField(int) line: not available
Child.jdoProvideFields(int[]) line: not available
JDOStateManagerImpl.provideFields(int[], FieldManager) line: 2600
InsertRequest.execute(StateManager) line: 251
ClassTable.insert(StateManager) line: 2888
RDBMSManager(MappedStoreManager).insertObject(StateManager) line: 180
JDOStateManagerImpl.internalMakePersistent() line: 3108
JDOStateManagerImpl.makePersistent() line: 3088
ObjectManagerImpl.persistObjectInternal(Object, FieldValues, StateManager, int, int) line: 1166
ObjectManagerImpl.persistObject(Object) line: 1017
JDOPersistenceManager(AbstractPersistenceManager).jdoMakePersistent(Object) line: 641
JDOPersistenceManager(AbstractPersistenceManager).makePersistent(Object) line: 666
DetachmentTester.save(PersistenceManagerFactory, Object) line: 39
DetachmentTester.main(String[]) line: 24

This exception is thrown because the PersistenceCapable instance is detached and jdoCopyKeyFieldsFromObjectId(...) requires the instance to have a Persistence Manager before being called (when the instance has a compound id that includes another PC instance).

In JPOX's PersistenceCapableMapping.setObjectAsValue(...) method, shouldn't [code]value[/value], when passed in be re-attached if it was a detached instance to begin with?

What's happening in my test case is that Child.parent is required to persist the Child instance, so InsertRequest.execute(...) calls the Child's JDOStateManagerImpl.provideFields(...) method. When this eventually gets down to the PCM.setObjectAsValue(...) method, though, the Child.parent field has never been re-attached and so when it calls the Parent's jdoCopyKeyFieldsFromObjectId(...) method, which expects its jdoGetPersistenceManager() to return something, a NullPointerException is thrown.

My test case is on another computer and I'll attach it right after I clean it up to match the requirements.

Sort Order: Ascending order - Click to sort in descending order
Karl M. Davis added a comment - 15/Jan/08 10:07 PM
Attached the test case.

Karl M. Davis added a comment - 15/Jan/08 11:28 PM
Here's a snippet of the reverse-engineered source the Parent class that indicates the problem:
    public void jdoCopyKeyFieldsFromObjectId(javax.jdo.spi.PersistenceCapable.ObjectIdFieldConsumer fc, Object oid)
    {
        if(fc == null)
            throw new IllegalArgumentException("ObjectIdFieldConsumer is null");
        if(!(oid instanceof PK))
            throw new ClassCastException("oid is not instanceof phmpro.detachtest.Parent$PK");
        PK o = (PK)oid;
        try
        {
            fc.storeObjectField(0, jdoGetPersistenceManager().getObjectById(o.grandparent, false));
            fc.storeStringField(1, o.name);
        }
        catch(Exception exception) { }
    }

That call to jdoGetPersistenceManager() is what throws the NPE.

Karl M. Davis added a comment - 25/Apr/08 10:02 PM
Just to clarify my earlier comment: it isn't the call to jdoGetPersistenceManager() that throws the NPE, it's the call to getObjectById(...) on the null result that does. In other words:
fc.storeObjectField(0, null.getObjectById(o.grandparent, false)); <-- throws an NPE

The empty catch block right there, though, means that the end user never sees the NPE itself, just whatever other errors it causes. The only way to even notice it happens is to Debug in Eclipse with exception breakpoints set.

Andy Jefferson added a comment - 25/May/10 08:28 PM
The previous exception doesn't happen in DataNucleus, however a different one does on the INSERT statement relating to not having one of the attached objects present (or something)

Andy Jefferson added a comment - 26/May/10 08:20 AM
SVN trunk now passes the provided test (PC object that is part of PK of the new Child object has to be swapped for the attached object).

"All good things come to those that wait"