I've been trying to map part of a legacy database and have run across a problem when using a one-to-many mapping with a foreign key referencing a non-primary key.
All is fine as long as the class containing the collection uses a single primary key. When the class uses a composite key however the following stack trace occurs:
Quote:
org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.ri3k.domain.Foo$Id.id
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:171)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:64)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:70)
at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:86)
at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:353)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:184)
at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:104)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:48)
at org.hibernate.engine.StatefulPersistenceContext.getCollectionOwner(StatefulPersistenceContext.java:678)
at org.hibernate.loader.Loader.readCollectionElement(Loader.java:993)
at org.hibernate.loader.Loader.readCollectionElements(Loader.java:646)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:591)
at org.hibernate.loader.Loader.doQuery(Loader.java:701)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:36)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:565)
at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:60)
at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716)
at org.hibernate.collection.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:454)
at org.hibernate.engine.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:797)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:241)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1860)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:48)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:42)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3044)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:395)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:375)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:139)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:195)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:103)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:815)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:808)
at com.ri3k.dao.SyndicateLineDaoImpl.findFooById(SyndicateLineDaoImpl.java:17)
at com.ri3k.dao.FooBarDaoIntTest.testMappingForFooBarWorksCorrectly(FooBarDaoIntTest.java:40)
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:585)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
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)
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
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:585)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:145)
... 54 more
My failing test classes and their mappings are:
Failing foo class
Code:
public class Foo {
public static class Id implements Serializable{
private static final long serialVersionUID = 865226439037071749L;
private Long id;
private Long id2;
public Id(Long id, Long id2){
this.id = id;
this.id2 = id2;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getId2() {
return id2;
}
public void setId2(Long id2) {
this.id2 = id2;
}
}
private Id id;
private Set<Bar> foobar;
private Long foobarId;
public Long getFoobarId() {
return foobarId;
}
public Set<Bar> getFoobar() {
return foobar;
}
public void setFoobar(Set<Bar> foobar) {
this.foobar = foobar;
}
public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
}
failing Foo mapping:Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ri3k.domain">
<class name="Foo" table="foo">
<composite-id name="id" class="com.ri3k.domain.Foo$Id">
<key-property name="id" column="id" type="java.lang.Long"/>
<key-property name="id2" column="id2" type="java.lang.Long"/>
</composite-id>
<set name="foobar" inverse="true" lazy="false" cascade="save-update">
<key column="group_id" property-ref="foobarId"/>
<one-to-many class="com.ri3k.domain.Bar"/>
</set>
<property name="foobarId" column="group_id" not-null="true" generated="insert" insert="false" update="false" access="field"/>
</class>
</hibernate-mapping>
Bar class:Code:
public class Bar {
private Long fooBarId;
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getFooBarId() {
return fooBarId;
}
public void setFooBarId(Long fooBarId) {
this.fooBarId = fooBarId;
}
}
Bar mapping:Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ri3k.domain.Bar" table="bar">
<id name="id" column="id" type="java.lang.Long">
<generator class="sequence">
<param name="sequence">bar_seq</param>
</generator>
</id>
<property name="fooBarId" column="group_id" />
</class>
</hibernate-mapping>
and the successful versions of foo:Code:
public class Foo {
private Long id;
private Set<Bar> foobar;
private Long foobarId;
public Long getFoobarId() {
return foobarId;
}
public Set<Bar> getFoobar() {
return foobar;
}
public void setFoobar(Set<Bar> foobar) {
this.foobar = foobar;
}
public Long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ri3k.domain">
<class name="Foo" table="foo">
<id name="id" column="id" type="java.lang.Long">
<generator class="sequence">
<param name="sequence">foo_seq</param>
</generator>
</id>
<set name="foobar" inverse="true" lazy="false" cascade="save-update">
<key column="group_id" property-ref="foobarId"/>
<one-to-many class="com.ri3k.domain.Bar"/>
</set>
<property name="foobarId" column="group_id" not-null="true" generated="insert" insert="false" update="false" access="field"/>
</class>
</hibernate-mapping>
Failing test case:Code:
public class FooBarDaoIntTest extends AbstractDaoIntTest{
FooBarDao fooBarDao = null;
public void testMappingForFooBarWorksCorrectly() throws Exception {
Long id = 1L;
Long id2 = 4L;
Long barId = 3L;
Id fooId = new Foo.Id(id, id2);
Foo foo= fooBarDao.findFooById(fooId);
assertEquals(1, foo.getFoobar().size());
assertEquals(barId, foo.getFoobar().iterator().next().getId());
}
public void setFooBarDao(FooBarDao fooBarDao) {
this.fooBarDao = fooBarDao;
}
}
Thanks for any help with this one