I seem to be unable to determine the run-time types of objects in a mapped class hierarchy using table-per-subclass (joined subclass). The error does only occur if the object is fetched lazyli. The fetched object is a IPersoon and a IRechtspersoon at the same time.
The intended functionality is that biljet.getSubject() returns either a IPersoon or a IRechtspersoon object.
Can somebody please supplyus with a hint as to how we can determine the object class at run-time correctly? Extensive searching in the documentation and this forum did not solve the problem.
After the code line
IBiljet biljet = getDao().getBiljetById(537); the object biljet looks like:
Code:
biljet Biljet (id=32)
_bezwaren PersistentSet (id=41)
beschikkingen HashSet<E> (id=39)
biljetnr 537
d_aanmaken Date (id=51)
d_biljet Date (id=54)
events HashSet<E> (id=55)
id 537
inserted Timestamp (id=56)
objectsoortid 1016
state 0
statussen HashSet<E> (id=58)
subject HibernateProxy$$EnhancerByCGLIB$$d7e60d94 (id=59)
CGLIB$BOUND true
CGLIB$CALLBACK_0 CGLIBLazyInitializer (id=66)
componentIdType null
constructed true
entityName "geotax.bib.impl.Subject"
getIdentifierMethod Method (id=76)
id Integer (id=81)
interfaces Class<T>[4] (id=84)
[0] Class<T> (org.hibernate.proxy.HibernateProxy) (id=61)
[1] Class<T> (geotax.bib.model.ISubject) (id=62)
[2] Class<T> (geotax.bib.model.IRechtspersoon) (id=63)
[3] Class<T> (geotax.bib.model.IPersoon) (id=64)
overridesEquals true
persistentClass Class<T> (geotax.bib.impl.Subject) (id=87)
replacement null
session SessionImpl (id=91)
setIdentifierMethod null
target null
version 1
1
The interfaces contains both IPersoon and IRechtspersoon. why?
Below is the testcase that illustrates the problem:
Code:
public class TestComparePersitentSubjects extends BibTestCase {
public void testComparePersistentSubjects() {
System.out.println("[test testComparePersistentSubjects]");
IBiljet biljet = getDao().getBiljetById(537);
ISubject reclamant = biljet.getSubject();
// Er is iets fout met de manier waarop personen/rechtspersonen
// uit de database komen: ze zijn zowel Persoon als Rechtspersoon.
if (reclamant instanceof IPersoon) {
assertFalse(reclamant instanceof IRechtspersoon);
} else {
assertFalse(reclamant instanceof IPersoon);
}
System.out.println("[ok]");
}
}
Execution of this test-case yields:
Code:
junit.framework.AssertionFailedError
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertFalse(Assert.java:34)
at junit.framework.Assert.assertFalse(Assert.java:41)
at geotax.bib.tests.TestComparePersitentSubjects.testComparePersistentSubjects(TestComparePersitentSubjects.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
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.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
This means that reclamant is an instance of both IPersoon and IRechtspersoon, which is not true (it is in fact an IPersoon).
Hibernate version: Hibernate-Version: 3.0.beta4
mappingbiljet.hbm.xml:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hiernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="geotax.bib.impl.Biljet" table="BIB_BILJET">
<cache usage="nonstrict-read-write"/>
<!-- GeoObject part -->
<id name="id" column="ID" type="integer"> <generator class="increment"/> </id>
<version name="version" unsaved-value="negative"/>
<property name="state" column="STATE" type="integer"/>
<property name="inserted" column="INSERTED" type="timestamp"/>
<!-- Object-specific part -->
<property name="biljetnr" column="BILJETNR" type="long" length="10"/>
<property name="ingangsdatum" column="DATUM_BILJET" type="date"/>
<property name="aanmaakdatum" column="AANMAAKDATUM" type="date"/>
<!-- Subject -->
<many-to-one name="subject" column="SUBJECTID" class="geotax.bib.impl.Subject"/>
<!-- TODO: Biljet heeft een set van Beschikkingen -->
<!-- Bezwaren-part -->
<set name="bezwaren" table="BIB_BEZWAAR" cascade="all" inverse="true" lazy="true">
<cache usage="nonstrict-read-write"/>
<key column="biljetid"/>
<one-to-many class="geotax.bib.impl.Bezwaar"/>
</set>
</class>
</hibernate-mapping>
Subject.hbm.xml:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hiernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="geotax.bib.impl.Subject" table="BIB_SUBJECT" proxy="geotax.bib.model.ISubject">
<cache usage="nonstrict-read-write"/>
<id name="id" column="ID" type="integer" unsaved-value="-1"> <generator class="increment"/> </id>
<version name="version" unsaved-value="negative"/>
<property name="state" column="STATE" type="integer"/>
<property name="inserted" column="INSERTED" type="timestamp"/>
<!-- Rechtspersoon part -->
<joined-subclass name="geotax.bib.impl.Rechtspersoon" table="BIB_RECHTSPERSOON" proxy="geotax.bib.model.IRechtspersoon">
<key column="ID"/>
<property name="verkorteBedrijfsnaam" column="VERKORTE_BEDRIJFSNAAM" type="string" length="55" />
</joined-subclass>
<!-- Persoon part -->
<joined-subclass name="geotax.bib.impl.Persoon" table="BIB_PERSOON" proxy="geotax.bib.model.IPersoon">
<key column="ID"/>
<property name="voorletters" column="VOORLETTERS" type="string" length="10" />
</joined-subclass>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():None, we use Springs' OpenSessionInViewFilter.
Code:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="mappingResources">
<list>
<!-- Eerst de klassen met 0 dependencies -->
<value>geotax/bib/dao/TTO.hbm.xml</value>
<value>geotax/bib/dao/Memo.hbm.xml</value>
<value>geotax/bib/dao/Participant.hbm.xml</value>
<value>geotax/bib/dao/Status.hbm.xml</value>
<value>geotax/bib/dao/Land.hbm.xml</value>
<value>geotax/bib/dao/Doctype.hbm.xml</value>
<value>geotax/bib/dao/Biljet.hbm.xml</value>
<value>geotax/bib/dao/Eventsoort.hbm.xml</value>
<!-- Nu klassen die alleen afhangen van een klasse met 0 depencies -->
<!-- Afspraak, Event <= Participant (has_a) -->
<value>geotax/bib/dao/Afspraak.hbm.xml</value>
<value>geotax/bib/dao/Event.hbm.xml</value>
<!-- Straat <== Land (has_a) -->
<value>geotax/bib/dao/Straat.hbm.xml</value>
<!-- Klassen die afhangen van een klasse met 1 depency -->
<!-- Adres <= Straat (has_a) -->
<value>geotax/bib/dao/Adres.hbm.xml</value>
<!-- WozBeschikking <= adres (has_a) -->
<value>geotax/bib/dao/WozBeschikking.hbm.xml</value>
<!-- Klassen die afhangen van klasse(n) met 1 of twee depencies -->
<!-- Subject <= Adres (has_a) -->
<value>geotax/bib/dao/Subject.hbm.xml</value>
<!-- Bezwaarschrift <= Adres (has_a), Subject (has_a) -->
<value>geotax/bib/dao/Bezwaarschrift.hbm.xml</value>
<value>geotax/bib/dao/Bezwaar.hbm.xml</value>
<value>geotax/bib/dao/Bezwaardeel.hbm.xml</value>
<value>geotax/bib/dao/Bezwaarsoort.hbm.xml</value>
<value>geotax/bib/dao/Document.hbm.xml</value>
<value>geotax/bib/dao/Grief.hbm.xml</value>
<value>geotax/bib/dao/Griefsoort.hbm.xml</value>
<value>geotax/bib/dao/Grond.hbm.xml</value>
<value>geotax/bib/dao/Overweging.hbm.xml</value>
<value>geotax/bib/dao/Vraag.hbm.xml</value>
<value>geotax/bib/dao/Vraagafhandeling.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.default_batch_fetch_size">25</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">false</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">false</prop>
</props>
</property>
</bean>
Full stack trace of any exception that occurs:There is no Exception.
Name and version of the database you are using:Code:
Oracle 9i Enterprise Edition Release 9.2.0.1.0 - Production
The generated SQL (show_sql=true):Code:
[test testComparePersistentSubjects]
Hibernate: select biljet0_.ID as ID0_, biljet0_.version as version10_0_, biljet0_.STATE as STATE10_0_, biljet0_.INSERTED as INSERTED10_0_, biljet0_.BILJETNR as BILJETNR10_0_, biljet0_.DATUM_BILJET as DATUM6_10_0_, biljet0_.AANMAAKDATUM as AANMAAKD7_10_0_, biljet0_.SUBJECTID as SUBJECTID10_0_ from BIB_BILJET biljet0_ where biljet0_.ID=?
Debug level Hibernate log excerpt: