-->
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: Inheritance inconsistency.
PostPosted: Wed May 31, 2006 6:29 am 
Newbie

Joined: Tue May 30, 2006 11:50 am
Posts: 4
Hibernate version: 3.1 and 3.2cr2

Name and version of the database you are using: Tested on PostgreSQL-7.4 and HSQLDB-2.0 and H2-0.9alpha

Inheritance type: Tested with "table per subclass" and "table per concrete class"

Hi,

I'm in front of a strange problem.

I have 3 classes : A, B and C.

A has a relation to B, and C extends B.

I only insert 2 instances in the database : one A and one C, linked by the relation between A and B.

When I retrieve my A, and I do a getB, I obtain an object which is an instance of B but not an instance of C.

In a junit test, I have :
Code:
        Session session = getSession(false);
        Criteria criteria = session.createCriteria(A.class);
        A a = (A)criteria.uniqueResult();
        B b = a.getB();
        assertTrue(b instanceof B);
        assertTrue(b instanceof C);
        session.close();


When I run the test, the line "assertTrue(b instanceof C);" fails :(

As I said previously, I only have 2 instances in my DB, it's impossible that I find a B which is not a C !

I inserted my data as follows :
Code:
        Session session = getSession(true);
        Transaction tx = session.beginTransaction();

        C cmano = new C();
        cmano.setTata(66);
        cmano.setToto(55);
        session.save(cmano);

        A amano = new A();
        amano.setB(cmano);
        session.save(amano);

        tx.commit();
        session.close();
        factory.close(); //When using H2 or HSQL, I need to close the factory


I tested it with hibernate 3.1 and 3.2cr2 but got the same problem...
I also tested it on Postgres 7.4, HSQL 2.0 and H2 0.9alpha and got exactly the same problem.
I reproduced the problem with both "per subclass" and "per concrete class" inheritance types.

I'm probably doing wrong somewhere but the fail keep being very strange...

If any of you have an idea, you would be welcome...

Best regards,

Arno.

--------------------------------------------------------------

I can give some details on my model:

A
Class
Code:
public class A {

    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

} //A

Mapping
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="org.codelutin.hibtest.inheritance.A" table="atable">
    <id type="string">
      <generator class="uuid.hex"/>
    </id>
    <many-to-one name="b" class="org.codelutin.hibtest.inheritance.B"/>
  </class>
</hibernate-mapping>


B
Class
Code:
public class B {

    private int toto;

    public int getToto() {
        return toto;
    }

    public void setToto(int toto) {
        this.toto = toto;
    }

} //B

Mapping
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="org.codelutin.hibtest.inheritance.B" table="btable">
    <id type="string">
      <generator class="uuid.hex"/>
    </id>
    <property name="toto" type="int"/>
  </class>
</hibernate-mapping>


C
Class
Code:
public class C extends B {

    private int tata;

    public int getTata() {
        return tata;
    }

    public void setTata(int tata) {
        this.tata = tata;
    }

} //C

Mapping
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <union-subclass name="org.codelutin.hibtest.inheritance.C" table="ctable"
      extends="org.codelutin.hibtest.inheritance.B">
    <property name="tata" type="int"/>
  </union-subclass>
</hibernate-mapping>


The test class
Code:
import java.util.Properties;
import junit.framework.TestCase;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class InheritanceTestMano extends TestCase {

    protected static SessionFactory factory;

    protected Properties getConfig(boolean create) {
        Properties config = new Properties();
        config.setProperty("hibernate.show_sql", "true");
        if (create) {
            config.setProperty("hibernate.hbm2ddl.auto", "create");
        }
        config.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        config.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
        config.setProperty("hibernate.connection.url", "jdbc:h2:data/hibtest");
        config.setProperty("hibernate.connection.username", "sa");
        config.setProperty("hibernate.connection.password", "");
        return config;
    }

    protected void createData() throws Exception {
        Session session = getSession(true);
        Transaction tx = session.beginTransaction();

        C cmano = new C();
        cmano.setTata(66);
        cmano.setToto(55);
        session.save(cmano);

        A amano = new A();
        amano.setB(cmano);
        session.save(amano);

        tx.commit();
        session.close();
        factory.close(); //When using H2 or HSQL, I need to close the factory
    }

    private Session getSession(boolean create) {
        if (factory == null) {
            Configuration cfg = new Configuration();
            cfg.addClass(A.class);
            cfg.addClass(B.class);
            cfg.addClass(C.class);
            cfg.setProperties(getConfig(create));
            factory = cfg.buildSessionFactory();
        }
        return factory.openSession();
    }

    public void testInheritance() throws Exception {
        Session session = getSession(false);
        Criteria criteria = session.createCriteria(B.class);
        B b = (B)criteria.uniqueResult();
        assertTrue(b instanceof B);
        assertTrue(b instanceof C);
        session.close();
    }

    public void testInheritanceFromA() throws Exception {
        Session session = getSession(false);
        Criteria criteria = session.createCriteria(A.class);
        A a = (A)criteria.uniqueResult();
        B b = a.getB();
        assertTrue(b instanceof B);
        assertTrue(b instanceof C);
        session.close();
    }

    public static void main(String[] args) throws Exception {
        InheritanceTestMano test = new InheritanceTestMano();
        test.createData();
    }

} //InheritanceTestMano


Top
 Profile  
 
 Post subject: no reply ?
PostPosted: Fri Jun 02, 2006 5:25 am 
Newbie

Joined: Tue May 30, 2006 11:50 am
Posts: 4
Hi all,

as nobody did answer my question, may I consider this as a potential bug ?

Please let me know if I should post to a hibernate development mailing list ?

Regards,

Arno.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 02, 2006 7:02 pm 
Senior
Senior

Joined: Tue Mar 09, 2004 2:38 pm
Posts: 141
Location: Lowell, MA USA
First, this is not a bug. This section of the Hibernate documentations describes why this is:

http://www.hibernate.org/hib_docs/v3/re ... ng-proxies

In short, you're getting back proxies which will fail an instanceof test. You have three options:

1.) on your many-to-one mapping define proxy="false", however this will cause the association to be egerly loaded.
2.) Use byte code instrumentation and use lazy="no-proxy"
3.) Declare an a proxy interface for your classes

I have had issuses with option #3 and I am trying to forumalte a test case for it. Using your code as an example, you'd need the following mapping:


Code:
<hibernate-mapping>
  <class name="org.codelutin.hibtest.inheritance.AImpl"
table="atable">
    <id type="string">
      <generator class="uuid.hex"/>
    </id>
    <many-to-one name="b" class="org.codelutin.hibtest.inheritance.BImpl"/>
  </class>
</hibernate-mapping>


Your code can still work with the interfaces, but your mappings need to define the concrete class. The trouble with proxy interfaces and inheritence is that while they solve the casting & instanceof check, Hibernate sometime returns the wrong proxy. So say you execute the following code:

Code:
B b = a.getB();
if(b instanceof C) {
   C c = (C) b;
   c.getFoo();
}


Once you call c.getFoo(), a class cast exception will be thrown and it may have the Proxy interface for A rather than C, even through the HibernateProxy instance that you're actually working with has it's implementation as CImpl. I'm going to post an example when I get some free time because it is an annoying, yet obscure issue.

Ryan-

_________________
Ryan J. McDonough
http://damnhandy.com

Please remember to rate!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 06, 2006 4:03 am 
Newbie

Joined: Tue May 30, 2006 11:50 am
Posts: 4
Hi,

First, thank you for your help.

I tried the two first solutions, as the third does not really match my 'real' case. (I only gave an illustration in this topic)

1.) proxy="false" => it works, fine (hopefully)
2.) proxy="no-proxy" => The problem is still the same.

Anyway, I will continue in these directions, thanks for the help :)

Best regards,

Arno.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 12, 2006 2:56 am 
Newbie

Joined: Tue May 30, 2006 11:50 am
Posts: 4
arnolelutin wrote:
as the third does not really match my 'real' case.

Hi,

I was mistaking, in fact the third solution is the best for me. I tested it, and all works fine :)

Thanks & regards,

Arno.


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.