users@glassfish.java.net

Toplink NullPointerException with compound primary key?

From: <glassfish_at_javadesktop.org>
Date: Wed, 10 Sep 2008 09:16:39 PDT

(I have attached my stack trace at the end of this message.)

I'm using Java 6 update 10 RC and Glassfish 9.1 build 49 (the latest as of yesterday).

Here's some background (and I'm happy and willing to supply any information that anyone might need to figure out whether this is a bug or not).

Here is my ER diagram (yay, ASCII art):

[code]
PartyEntity <--- PartyNameBinding ---> NameEntity
----------- ---------------- ----------
id:long (PK) partyID:long (FK, PK) id:long (PK)
                 type:String (PK)
                 nameID:long (FK)
[/code]
So: a PartyNameBinding is identified by a combination of a party and a type (so you can designate a particular name for a particular party with a particular type or key, e.g. "firstName").

My PartyEntity's identifier is, in JPA land, a @Generated value. I'm using IDENTITY.

My NameEntity's identifier is also a @Generated value.

My PartyNameBinding's identifier is an @EmbeddedId. The @Embeddable class defines two fields, like this:

[code]
PartyNameBinding.PK
-------------------
partyID:long
type:String
[/code]
The PartyEntity maintains a map of these bindings, indexed by their primary key:
[code]
  @OneToMany(mappedBy="partyEntity", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
  protected Map<PartyNameBindingEntity.PK, PartyNameBindingEntity> getNameBindings() {
    if (this.nameBindings == null) {
      this.nameBindings = new SerializableObservableMap<PartyNameBindingEntity.PK, PartyNameBindingEntity>();
    }
    return this.nameBindings;
  }
[/code]

Now, when I create a PartyEntity in memory, and stuff a PartyNameBindingEntity into its name bindings map, obviously the binding has something like "0" set as its partyID, since the new PartyEntity hasn't been persisted yet, and hence doesn't have a "true" ID set on it yet. This may or may not be relevant down the road.

So then I persist the new PartyEntity. Everybody seems happy until--it appears--Toplink begins trying to create a primary key for what I [i]think[/i] must be the binding (via CMP3Policy.createPrimaryKeyInstance()). Recall that the PK that it's trying to create is probably? I have to assume since the log message doesn't tell me? my @Embeddable PK class (the one with the long partyID and the String type).

At any rate, it tells me that it bombs out with a NullPointerException.

I am fully expecting there to be some pilot error in here somewhere, but it is interesting that the stack trace doesn't mention any of my classes, and I take great care to ensure in my code that there are no null references (i.e. there aren't any null keys in the binding map, etc.).

Is there a better way to troubleshoot what could be going wrong here? I'm also open to alternative mapping approaches.

Thanks,
Laird

And now the stack trace:
[code]
java.lang.NullPointerException
        at oracle.toplink.essentials.internal.ejb.cmp3.base.CMP3Policy.createPrimaryKeyInstance(CMP3Policy.java:217)
        at oracle.toplink.essentials.internal.queryframework.MapContainerPolicy.keyFrom(MapContainerPolicy.java:309)
        at oracle.toplink.essentials.internal.queryframework.MapContainerPolicy.addInto(MapContainerPolicy.java:123)
        at oracle.toplink.essentials.internal.queryframework.ContainerPolicy.mergeChanges(ContainerPolicy.java:700)
        at oracle.toplink.essentials.mappings.CollectionMapping.mergeChangesIntoObject(CollectionMapping.java:683)
        at oracle.toplink.essentials.internal.descriptors.ObjectBuilder.mergeChangesIntoObject(ObjectBuilder.java:2114)
        at oracle.toplink.essentials.descriptors.changetracking.DeferredChangeDetectionPolicy.updateWithChanges(DeferredChangeDetectionPolicy.java:217)
        at oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.updateChangeTrackersIfRequired(RepeatableWriteUnitOfWork.java:327)
        at oracle.toplink.essentials.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:271)
        at oracle.toplink.essentials.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:246)
        at oracle.toplink.essentials.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:202)
        at oracle.toplink.essentials.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:2668)
        at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1044)
        at oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:496)
        at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1126)
        at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:2458)
        at oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:277)
        at oracle.toplink.essentials.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:131)
        at oracle.toplink.essentials.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:91)
        at com.sun.enterprise.distributedtx.J2EETransaction.commit(J2EETransaction.java:423)
        at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.commit(J2EETransactionManagerOpt.java:371)
        at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:3792)
        at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3571)
        at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1354)
        at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1316)
        at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:210)
        at com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke(EJBObjectInvocationHandlerDelegate.java:117)
        at $Proxy42.save(Unknown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
        at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
        at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
        at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
[/code]
[Message sent by forum member 'ljnelson' (ljnelson)]

http://forums.java.net/jive/thread.jspa?messageID=298391