Hibernate Patterns: polymorphic many-to-one

Recently I found myself in a situation where I needed to define a persistent many-to-one relationship in which the concrete class of the many side could vary. In the past I’d had some issues with class inheritence and Hibernate, which can get sticky because of Hibernate proxies: you can’t always cast the proxies to the desired type. Since I had to find a way to make this work, I decided to give interface inheritence a try.

Recently I found myself in a situation where I needed to define a persistent many-to-one relationship in which the concrete class of the many side could vary. In the past I’d had some issues with class inheritence and Hibernate, which can get sticky because of Hibernate proxies: you can’t always cast the proxies to the desired type. Since I had to find a way to make this work, I decided to give interface inheritence a try. I started with a lightweight interface for a persistent object:
 <br>package example;<br>  <br>import java.io.Serializable;   <br><br>/** <br> * Note that ID could be more generally defined as Serializable, <br> * but long worked best in this situation <br> */ <br>public interface PersistentLite extends Serializable <br>{    <br>   long getId(); <br>   void setId(long id); <br>}

The relationship is the classic parent-child relationship. This is our parent interface:

 <br>package example;  <br><br>import java.util.Set;  <br><br>/**  <br> * In practice, the set of children should be restricted to instances of Child, <br> * but type parameters do not display well in <span class="caps">HTML</span>,  <br> * so we use the raw type in this example.  <br> */ <br>public interface Parent extends PersistentLite <br>{<br>   Set getChildren();<br>   void setChildren(Set children);<br>}

Here’s the child. In this case, the child also has a couple of different implementations, so it is also defined as an interface:

package example;<br><br>public interface Child extends PersistentLite<br>{<br>   Parent getParent();<br>   void setParent(Parent parent);<br>}

Here are the mappings for parent and child:

<hibernate><br>  <class table="parent" name="example.Parent"><br>    <id name="id"><generator class="native"/></id><br>    <discriminator/>        <br>    <set inverse="true" cascade="all-delete-orphan" name="children"><br>      <key column="parent"/><br>      <one-to-many class="example.Child"/><br>    </set><br>  </class><br></hibernate> <hibernate><br>  <class table="child" name="example.Child"><br>    <id name="id"><generator class="native"/></id><br>    <discriminator/><br>    <many-to-one name="parent"/><br>  </class><br></hibernate> 

You would then add implementation classes and mappings, these are representative:

package example;<br><br>import java.util.*;<br><br>public class ParentImpl implements Parent<br>{<br>   private long id;<br>   private Set children = new TreeSet(); <br>   private String extraData;<br><br>   public long getId()<br>   {<br>      return id;<br>   }<br><br>   public void setId(long n)<br>   {<br>      id = n;<br>   }<br>   <br>   public Set getChildren()<br>   {<br>      return children;<br>   }<br><br>   public void setChildren(Set set)<br>   {<br>      children = set == null ? new TreeSet() : set;<br>   }<br><br>   public String getExtraData()<br>   {<br>      return extraData;<br>   }<br><br>   public void setExtraData(String s)<br>   {<br>      extraData = s;<br>   }<br>}  <br>package example;<br>public class ChildImpl implements Child<br>{<br>   private long id;<br>   private Parent parent;<br>   private String extraData;<br>   <br>   public long getId()<br>   {      <br>      return id;<br>   }<br><br>   public void setId(long n)<br>   {<br>      id = n;<br>   }<br><br>   public Parent getParent()<br>   {<br>      return parent;<br>   }<br><br>   public void setParent(Parent p)<br>   {<br>       parent = p;<br>   }<br><br>   public String getExtraData()<br>   {<br>      return extraData;<br>   }<br><br>   public void setExtraData(String s)<br>   {<br>      extraData = s;<br>   }<br>} <hibernate><br>  <subclass extends="example.Parent" name="example.ParentImpl"><br>    <property name="extraData"/><br>  </subclass><br></hibernate>  <hibernate><br>  <subclass extends="example.Child" name="example.ChildImpl"><br>    <property name="extraData"/><br>  </subclass><br></hibernate>

The key insight is this: because the interfaces are mapped, Hibernate generates proxies that implement the interface, which eliminates a lot of potential casting problems. By contrast, if you use class inheritance, Hibernate can only generate proxies that implement the interface which the class exposes to Hibernate, and is not necessarily the same as the interface exposed to the system at large. This causes confusion. Moreover, since a lot of casting issues can occur from inside the subclass, via private methods and data, using an interface eliminates a lot potential problems because the interface is well-defined. You could still run into issues when casting, but they are greatly reduced if the interface is properly defined. Finally, using a lightweight interface as the basis of the relationship gives the implementation the flexibility to inherit from a richer base class if desired.

Jed Prentice