-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Problem with polymorphic lazy load despite proxy interfaces
PostPosted: Mon Oct 03, 2005 6:48 am 
Newbie

Joined: Mon Sep 19, 2005 4:30 am
Posts: 11
Hello,

has anyone had the same problem?

I work with a mapping of 200 persistent classes where the most important classes live in two hierarchies, connected by an association at the highest level. I tried several ways to get around the problem described below. Meanwhile I believe it might be a current limitation of hibernate - although not a fundamental one (please let me know if I'm wrong in either direction).

The essential setting to reproduce the error is as follows: given is a hierarchy of three Classes:

Partner, Person, Organisation

Persons and Organisations are Partners, but a Person is not an Organisation and an Organisation is not a Person.

All three classes are mapped with proxy Interfaces (IPartner, IPerson, IOrganisation) in order to avoid ClassCastExceptions when lazily loading Partners.

All three classe implement the method istPerson() (which is a kind of a custom instanceof method). It is important that this method does not need any persistent data.

Then:
Quote:
Only one of the following calls to istPerson() produces a Class Cast exception:


Code:
        IPartner p1 = (IPartner) s.load(Partner.class, person1.getId());
        p1.istPerson();

        IPartner p2 = (IPartner) s.load(Partner.class, organisation1.getId());       
        p2.istPerson();


The debugger shows me, that the proxy of Partner implements all three interfaces (which all contain the method istPerson())
It seems that hibernate chooses the first Interface containing a method with a matching signature. But then the chosen method belongs to a specific Interface e.g. IPerson, causing an Error if invoked on a target implementign an other Interface, e.g. IOrgansiation (this ist true even if the Interface contains a Method with the same signature).

Note: No Class Cast Exception arises if we call getName() – which is a Method retrieving persistent data - on p1 an p2.

I would appreciate any comments on this

lnz

I'm working with hibernate 3.0.5

enclosed: mappings, java code and exception

Code:



   <class  name="Partner"
       proxy="IPartner"
      table="PARTNER"
      discriminator-value="partner">
      <id name="id" type="long">
         <column name="id" not-null="true"/>
         <generator class="native"/>
      </id>
      <discriminator column="HIBERNATE_TYPE"
                                     type="string" />
      <property name="name">
         <column name="NAME"/>
      </property>   
   </class>

   <subclass name="Person"
             extends="Partner"
             proxy="IPerson"
             discriminator-value="person">
   </subclass>

   <subclass name="Organisation"
             extends="Partner"
             proxy="IOrganisation"
             discriminator-value="organisation">
   </subclass>

public class Person extends Partner implements IPerson {

    Person() {}
   
    public Person(String name) {
        super(name);
    }

    public boolean istPerson() {
        return true;
    }

    public boolean istOrganisation() {
        return false;
    }

}

public class Partner implements IPartner {
    private Long id;
    private String name;
   
    Partner(){
    }
   
    public Partner(String name) {
        this.name = name;
    }
   
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean istPerson() {
        return false;
    }

    public boolean istOrganisation() {
        return false;
    }
}

public class Organisation extends Partner implements IOrganisation {
    public Organisation(String name) {
        super(name);
    }

    Organisation() {}
   
    public void setDatumOrganisation(Date datumOrganisation) {
        this.datum = datumOrganisation;
    }

    public boolean istPerson() {
        return false;
    }

    public boolean istOrganisation() {
        return true;
    }
}


java.lang.ClassCastException
   at at.hibernate3.polyquery3.IOrganisation$$FastClassByCGLIB$$c29c383e.invoke(<generated>)
   at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
   at org.hibernate.proxy.CGLIBLazyInitializer.intercept(CGLIBLazyInitializer.java:137)
   at org.hibernate.proxy.HibernateProxy$$EnhancerByCGLIB$$6a493d5b.istPerson(<generated>)
   at at.hibernate3.polyquery3.MainTest.testLazyPoly(MainTest.java:217)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:324)
   at junit.framework.TestCase.runTest(TestCase.java:154)
   at junit.framework.TestCase.runBare(TestCase.java:127)
   at junit.framework.TestResult$1.protect(TestResult.java:106)
   at junit.framework.TestResult.runProtected(TestResult.java:124)
   at junit.framework.TestResult.run(TestResult.java:109)
   at junit.framework.TestCase.run(TestCase.java:118)
   at junit.framework.TestSuite.runTest(TestSuite.java:208)
   at junit.framework.TestSuite.run(TestSuite.java:203)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)






Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 03, 2005 7:48 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Yes, it is a known lazy loading limitation, hibernate can not know runtime type before proxy is initialized.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 03, 2005 11:26 am 
Newbie

Joined: Mon Sep 19, 2005 4:30 am
Posts: 11
baliukas wrote:
Yes, it is a known lazy loading limitation, hibernate can not know runtime type before proxy is initialized.


I have two points:


First: this sounds like if initializing the proxy would help,
but this seems not to be the case since

Code:
        IPartner p1 = (IPartner) s.load(Partner.class, person1.getId());
        IPartner p2 = (IPartner) s.load(Partner.class, organisation1.getId());
        p1.getName();
        p2.getName();
        p2.istPerson();
        p1.istPerson();


should initialize the proxy (with the getName() Method), but the Exception occurs as described above (only for one of the two calls p2.istPerson() an p1.istPerson(); change the order the istPerson() Statements, if the first one causes the Exception).

Second: I think hibernate could do something about it, since the exception happens within the proxy - it could try to generate different istPerson() Method invocations - one for each of the istPerson() Methods of those interfaces (all implemented by the proxy) that contain a Method with this signature. The first one not causing a ClassCastException would be the right one. Don't you think so?

lnz


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 24, 2005 1:17 pm 
Newbie

Joined: Mon Sep 19, 2005 4:30 am
Posts: 11
for a discussion of this see

http://forum.hibernate.org/viewtopic.php?t=950127


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 24, 2005 5:36 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Workaround is to use base interface with single "istPerson()" method, it is possible to "detect" correct method in lazy initializer, but it will be too slow (reflective method lookup per call)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.