Hibernate version: 3.0b4
[n]mapping (partial)[/b]:
<class name="Project" table="PROJECT" lazy="false" >
.... omitted properties ...
<set name="objectRefs"
inverse="true"
lazy="false"
cascade="all,delete-orphan">
<key column="PROJECT_ID"/>
<one-to-many class="ProjectObjectRef"/>
</set>
</class>
<class name="NetworkObjectRef" table="OBJ_REFS" discriminator-value="NOR" lazy="false" >
.... omitted properties ...
<any name="ref" id-type="int" meta-type="string" cascade="save-update">
<meta-value value="TP" class="TP"/>
<meta-value value="NE" class="NE"/>
... other types ...
<column name="REF_TYPE" length="10"/>
<column name="OBJ_ID"/>
</any>
</class>
<subclass name="ProjectObjectRef" extends="NetworkObjectRef" discriminator-value="POR" lazy="false">
<many-to-one name="owner"
lazy="false"
column="PROJECT_ID"
class="Project"/>
</subclass>
I'm having all sorts of trouble with implementing hashCode and equals
for the following model:
(the Project<->ProjObjRef association is a bi-directional assoc.)
Note: for testing purposes, lazy is turned off for all these mappings.
Code:
+---------+ +--------------+
| Project | <>----*> | ProjObjRef |
| | |--------------|
| |<----------- owner | +----------+
+---------+ | objRef:any---------->| NetObj |
+--------------+ +----------+
The current obstacle I'm facing is to do with proxies and cglib. My aim is
to remove an element from a set. I'll describe the sequence of events that lead to the problem first:
1. load a Project instance (p) from the db using Session.get(obj, id)
2. obtain a reference to an instance of NetObj (n) by following other
criteria.
3. perform
Code:
objectRefs.remove( new ProjectObjectRef( this, object));
where
this is the current project, p and object is the reference to a
NetworkObject.
hashCode() and equals() are overriden for all these classes and they are
matched using candidate keys.
When the call to
remove happens, the set contains an instance of a
ProjectObjectRef which has an initialised
owner member, pointing to the
current project (to be expected since the project was loaded into the
session) and a reference pointing to a CGLIB enhanced version of
NetworkObject (n above).
The problem is that the NetworkObject reference, n above is an instance
of a CGLIB enhanced class, which was obtained by following references
from another object leading to that particular reference. When HashSet
calls the equals() method on the element it finds (as a result of calling
hashCode, it finds an instance of ProjectObjectRef with the same
hashCode), that element has the NetworkObject reference also pointing
to the same instance that the key object, passed to
remove(), has.
However, that
equals() invocation is intercepted by the CGLIB
initializer and it is being passed the second reference (still a reference to
the CGLIB proxy). CGLIB then proceeds to invoke the
equals()
method on the proxy target, the real NetworkObject ref, passing the arg
that was passed down to it to the method and this is where the problem
is: the
equals() method on NetworkObject is being passed a CGLIB
proxy as the object to compare and the fields of this object (as a derived
class of NetworkObject) are not initialised and so the method fails.
How do I go about performing this removal of object from the set?