Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] @ManyToOne and hashCode

Hi Phillip,

On Jun 28, 2012, at 7:20 PM, Phillip Ross wrote:

Ah good old hashCode fun :)

Yea, a great mind bending exercise when you throw JPA in the mix.



Your stack trace indicates that the NPE is happening in the Kitten
hashCode function when the instance is being placed in the collection.
You may just have to use more aggressive null checking in your
hashCode method(s).

Here's the odd thing. When I run a unit test which persists 3 kittens to the same owner in the same TX, the NPE does not happen on the same Kitten every time. It almost seems random.

In regard to your point about more aggressive null checks in Kitten's hashCode(); I could check for a null Owner. However, that persists a new Kitten only if it can look up the owner so the owner that is being set is never NULL.  In fact when I step through this code when it experiences the NPE I can see that the owner is not null and then I can see at some eclipselink code calls Kitten.hashCode and owner on that kitten object is indeed NULL! 

I guess to truly see what is happening here I will need to get the eclipselink 2.3.2 source and step through all of this. Judging from the stack trace this seems to be some sort of post transactional part of the lifecycle. I'm guess from the method names that this part of the lifecycle is merging the new changes back into the session. This is what lead to my speculation that the new Kitten had been associated with an Owner whose hash code was different then it was at the start of the session (perhaps due to the olversion reving) and therefore this code looked it up with the old code and got a NULL and that's why Kitten sees its owner as NULL at this point in the lifecycle. That's my best guess short of downloading the Eclipselink 2.3.2 source and stepping through all of this. :-)

-Noah



In my projects I absolutely exclude the version field form the hash
code method.  I exclude the id field as well.  Actually, I only
compute it once, store it in a transient property in the entity and
return the cached value on subsequent calls to hash code.  It looks
and feels convoluted but it works for my projects :)


On Thu, Jun 28, 2012 at 1:12 PM, Noah White <emailnbw@xxxxxxxxx> wrote:
I have an entity which has a ManyToOne relationship expressed like so:

Kitten:

@ManyToOne(optional = false)
@JoinColumn(name = "USER_USERID", nullable = false)
private User owner;


On the other side of the relationship I have:

Owner:

@OneToMany(mappedBy = "owner")
@PrivateOwned
private Set<Kittens> kittens;

The Kitten class has a hashCode that looks like:

@Override
public int hashCode() {
       int result = name.hashCode();
       result = 31 * result + (group != null ? group.hashCode() : 0);
       result = 31 * result + owner.hashCode();
       return result;
}

I have a unit test that exercises creating some new Kittens. I am seeing NPEs in its hashCode when eclipselink is inside IndirectSet.add.  I'm not sure what part of the eclipselink lifecycle this is or why this is happening since on entity creation the user being assigned the ownership if fetched, assigned, and then the new kitten is added to the owner entities set of kittens. That code looks like this and is inside an EJB method:

Set targetOwnerKittens = owner.getKittens();  //owner is NOT NULL and is a managed object here which was previously looked up with em.find

//kitten was passed into the method and these are just there to insure that id and olversion are clear prior to persist
kitten.setKittenId(0);   // id - sequence generated long - this just makes sure it is zero prior to persist
kitten.setOLVersion(0);

kitten.setOwner(owner);
em.persist(kitten);
targetOwnerKittens.add(kitten);

The exception I get is below. Could this be an issue with Owner's hash code and Eclipselink trying to look it up from its cache which is keyed off a hashcode that has since changed this it returns a null? The only thing in the Owner hashCode that might change is the olVersion.  Should the optimistic lock field not be included in hashCode?

TIA,

-Noah

java.lang.NullPointerException
  at com.foo.KittenEntity.hashCode(KittenEntity.java:130)
  at java.util.HashMap.put(HashMap.java:389)
  at java.util.HashSet.add(HashSet.java:217)
  at org.eclipse.persistence.indirection.IndirectSet.add(IndirectSet.java:173)
  at org.eclipse.persistence.internal.queries.CollectionContainerPolicy.addInto(CollectionContainerPolicy.java:68)
  at org.eclipse.persistence.internal.queries.ContainerPolicy.mergeChanges(ContainerPolicy.java:1093)
  at org.eclipse.persistence.mappings.CollectionMapping.mergeChangesIntoObject(CollectionMapping.java:1334)
  at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeChangesIntoObject(ObjectBuilder.java:3409)
  at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:744)
  at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:617)
  at org.eclipse.persistence.internal.sessions.MergeManager.mergeChanges(MergeManager.java:267)
  at org.eclipse.persistence.mappings.ObjectReferenceMapping.mergeIntoObject(ObjectReferenceMapping.java:462)
  at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeIntoObject(ObjectBuilder.java:3466)
  at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeChangesIntoObject(ObjectBuilder.java:3400)
  at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:744)
  at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:617)
  at org.eclipse.persistence.internal.sessions.MergeManager.mergeChanges(MergeManager.java:267)
  at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.mergeChangesIntoParent(UnitOfWorkImpl.java:3254)
  at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.mergeChangesIntoParent(RepeatableWriteUnitOfWork.java:370)
  at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.mergeClonesAfterCompletion(UnitOfWorkImpl.java:3386)
  at org.eclipse.persistence.transaction.AbstractSynchronizationListener.afterCompletion(AbstractSynchronizationListener.java:213)
  at org.eclipse.persistence.transaction.JTASynchronizationListener.afterCompletion(JTASynchronizationListener.java:79)
  at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:537)
  at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855)
  at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5136)
  at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4901)
  at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2045)
  at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1994)
  at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
  at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users


Back to the top