News from Dec 16, 2008

  2008/12/16
ClassCastException in loading subclasses in Hibernate
Last changed: Dec 16, 2008 14:13 by Sven Filatov
Labels: hibernate, orm

Recently we had a problem with Hibernate (version 3.2.6) mapping with subclasses that threw a ClassCastException upon casting to a concrete subclass.

The mapping file:

<class name="..." table="...">
  <many-to-one name="pet" column="..." not-null="true"/>
</class>

<class name="Pet" table="...">
  <id name="id" column="...">
    <generator .../>
  </id>
  
  <discriminator formula="type"/>
  
  <subclass name="Cat" discriminator-value="cat">
    <join table="...">
      <key column="..."/>
    </join>
  </subclass>

  <subclass name="Dog" discriminator-value="dog">
    <join table="...">
      <key column="..."/>
    </join>
  </subclass>
</class>

The code:

class Pet {
  boolean isCat() {
    return this instanceof Cat;
  }
}

Pet pet = ...; 
if (pet.isCat()) {
  Cat cat = (Cat) pet; // throws ClassCastException!
  ...
}

We get the instance of pet through a many-to-one relation with Pet on its one end.

In the code snippet above, the actual type of pet is something like Pet$$EnhancerByCGLIB$$ccc3caa7 that is a direct subclass of Pet (pet.getClass().getSuperclass() returns Pet). But its only relation to Cat is that it "behaves" like one: the method boolean isCat() is proxied to return true.

Turned out that the exception is caused by loading the pet subclass object lazily. The problem is quite easy to fix with adding lazy="false" to <many-to-one/> element.

More information about such a case (including other options for fixing the problem) can be found from a Hibernate forum.

Posted at 16 Dec @ 2:03 PM by Sven Filatov | 0 Comments