Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Hibernate sometimes load instances of an incorrect subclass?

we have a strange problem with hibernate we can't explain.

What we have:

  1. one abstract class and two subclass of it. Let call them A, SubA1, SubA2
  2. we have another abstract class and some subclasses. Let call B, SubB1, SubB2.
  3. There is many-to-one relation between SubB1 and A.
  4. The hibernate mappings for classes A and B look like:

    <hibernate-mapping>
    
      <class name="A" table="A" lazy="false">
    
        <id name="id" column="ID" type="java.lang.Integer">
          <generator class="org.hibernate.id.enhanced.TableGenerator">
            <param name="segment_value">a</param>
          </generator>
        </id>
    
        <version name="olVersion" column="VERSION" type="integer" unsaved-value="negative" />
    
        <joined-subclass name="SubA1" table="SUB_A1" lazy="false">
          <key column="ID_A" foreign-key="FK_SUB_A1_A"/>
          <property name="p1" column="p1" length="255" unique="true"/>
          <property name="p2" column="p2" length="255" not-null="true" />
        </joined-subclass>
    
        <joined-subclass name="SubA2" table="SUB_A2" lazy="false">
          <key column="ID_A" foreign-key="FK_SUB_A2_A"/>
          <property name="p3" column="p3" length="255" not-null="true" unique="true" />
          <property name="p4" column="p4" length="4000" />
        </joined-subclass>
    
      </class>
    
    </hibernate-mapping>
    

and

<hibernate-mapping>

  <class name="B" table="B" lazy="false">

    <cache usage="read-write"/>

    <id name="id" column="ID" type="java.lang.Integer">
      <generator class="org.hibernate.id.enhanced.TableGenerator">
        <param name="segment_value">b</param>
      </generator>
    </id>

    <version name="olVersion" column="VERSION" type="integer" unsaved-value="negative" />

    <joined-subclass name="SubB1" table="SUB_B1" lazy="false">
      <key column="ID_B" foreign-key="FK_SUB_B1_B"/>
      <many-to-one name="subA" column="ID_A" not-null="false" update="false" foreign-key="FK_SUB_B1" lazy="false" class="A"/>
    </joined-subclass>

  </class>

</hibernate-mapping>

Now the question: sometimes hibernate loads items of SubA2 as instances of SubA1 by loading items of SubB1, but not all items will casted wrong, only a few of them and everytime not the same items.

Maybe someone can explain, what is going wrong or what is wrong with our hibernate mappings.

Thank you in advance.

Ps. This problem occurs for:

  • JDK 1.7.71
  • Oracle 12g
  • Hibernate 3.6.10

I didn't try for other configuration.

Unfortunately, I don't have sample application, but I also can't give the source code of the real applicaton.

like image 602
Tima Avatar asked Sep 11 '15 18:09

Tima


1 Answers

I think your hibernate mappings are right. So if you have errors I am sure it happens on casting time. I faced with this problem many times, and I always solved it using Visitor Pattern.

Another advantage of Visitor Pattern is that you don't need to force lazy=false, because it solves perfectly real type of a proxied object.

How to solve your problem

I recommend you to create a Visitor class which implements two visit methods for every A concrete subclass:

  • void visit(SubA1 object)
  • void visit(SubA2 object)

The implementation of both methods is the code you want to execute when A instance is a SubA1 or a SubA2 concrete class. I put void return, but obviously you can change it.

On the other hand, A class has to add an abstract visit method public abstract void visit(Visitor visitor);. Once again, I put void return, but you have to adapt it to the return type of visit methods.

SubA1 and SubA2 has to implement this method as follows:

public void accept(Visitor visitor) {
    visitor.visit(this);
}

This way, when you run this code objectA.accept(visitor) Java has to resolve in runtime the real type of objectA without casting, and with no errors. It really works, I am using it for years with Hibernate 3.x and 4.x.

Visitor Pattern documentation

Here you have a really nice article Proxy Visitor Pattern where you can find how to apply visitor pattern to hibernate when using proxied and non proxied objects.

Hope it helps!

like image 185
malaguna Avatar answered Oct 05 '22 23:10

malaguna