-->
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.  [ 9 posts ] 
Author Message
 Post subject: subclass/inheritance not working with annotations but xml ok
PostPosted: Fri Feb 15, 2008 10:58 am 
Newbie

Joined: Wed Feb 13, 2008 6:01 am
Posts: 8
Hi

I am having trouble mapping the single table inheritance with annotations. I have pasted the code below and it shows the version with annotations and the xml mapping file. For the test I am explicitly using an AnnotationConfiguration() and a classic Configuration() so I can exercise the mapping and the annotations. When I use the mapping file with the model below it works just fine but when I use the annotations it breaks. I would like to use the annotations because I would like to use JPA and when I substitute Toplink for Hibernate it works just fine so this must be down to Hibernates implementation details.

Hibernate version:

Hibernate 3.2.5

Mapping documents:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping
package="entity.test"
default-access="property">

<class name="Person" abstract="true" proxy="Person">
<id name="id">
<generator class="increment"/>
</id>

<discriminator
type="string"
column="type" />

<property name="name"
not-null="true"/>

<many-to-one name="parent"/>

<set name="children" inverse="true">
<key column="parent"/>
<one-to-many class="Parent"/>
</set>

<subclass name="Parent"
discriminator-value="PARENT" proxy="Parent">

<property name="job"/>
</subclass>

<subclass name="Child"
discriminator-value="CHILD" proxy="Child">

</subclass>
</class>


<class name="Car">
<id name="id">
<generator class="increment"/>
</id>

<property name="colour"
not-null="true"/>

<property name="make"
not-null="true"/>

<many-to-one name="owner"
lazy="false"/>

</class>

</hibernate-mapping>



@Entity
@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
@org.hibernate.annotations.ForceDiscriminator
@Table(name = "PERSON")
public abstract class Person {

@Id
@GeneratedValue()
private Long id;

private String name;

@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
private Person parent;

@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, mappedBy = "parent")
private Set<Person> children = new HashSet<Person>(0);

protected Person() {}

// getters and setters....

}



@Entity
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("PARENT")
@org.hibernate.annotations.ForceDiscriminator
@Table(name = "PERSON")
public class Parent extends Person {

private String job;

}



@Entity
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("CHILD")
@org.hibernate.annotations.ForceDiscriminator
@Table(name = "PERSON")
public class Child extends Person {

}


@Entity
public class Car {

@Id
@GeneratedValue()
private Long id;

private String make;

private String colour;

@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
private Person owner;

public Car() {}
}



Code between sessionFactory.openSession() and session.close():

session.beginTransaction();

//create parent
Parent parent = new Parent();
parent.setName("parent");
parent.setJob("fireman");

//create child
Child child = new Child();
child.setName("child");

//create car
Car car = new Car();
car.setColour("red");
car.setMake("honda");

//set up relationships
parent.getChildren().add(child);
child.setParent(parent);
car.setOwner(parent);

//persist all
session.persist(parent);
session.persist(child);
session.persist(car);

session.flush();

session.getTransaction().commit();

//clear so we have a clean slate for queries
session.clear();


session.beginTransaction();

// get some persons
List<Person> persons = session.createQuery("select p from Person p").list();


session.getTransaction().commit();



Full stack trace of any exception that occurs:

org.hibernate.jdbc.AbstractBatcher.log(AbstractBatcher.java:401) 2008-02-15 14:50:04,734 [main] DEBUG -
select
child0_.id as id0_,
child0_.name as name0_,
child0_.parent_id as parent5_0_
from
PERSON child0_
Hibernate:
select
child0_.id as id0_,
child0_.name as name0_,
child0_.parent_id as parent5_0_
from
PERSON child0_
org.hibernate.type.NullableType.nullSafeGet(NullableType.java:172) 2008-02-15 14:50:04,749 [main] DEBUG - returning '1' as column: id0_
org.hibernate.type.NullableType.nullSafeGet(NullableType.java:172) 2008-02-15 14:50:04,749 [main] DEBUG - returning 'parent' as column: name0_
org.hibernate.type.NullableType.nullSafeGet(NullableType.java:166) 2008-02-15 14:50:04,749 [main] DEBUG - returning null as column: parent5_0_
org.hibernate.type.NullableType.nullSafeGet(NullableType.java:172) 2008-02-15 14:50:04,765 [main] DEBUG - returning '2' as column: id0_
org.hibernate.type.NullableType.nullSafeGet(NullableType.java:172) 2008-02-15 14:50:04,765 [main] DEBUG - returning 'child' as column: name0_
org.hibernate.type.NullableType.nullSafeGet(NullableType.java:172) 2008-02-15 14:50:04,765 [main] DEBUG - returning '1' as column: parent5_0_
org.hibernate.jdbc.AbstractBatcher.log(AbstractBatcher.java:401) 2008-02-15 14:50:04,781 [main] DEBUG -
select
person0_.id as id0_,
person0_.name as name0_,
person0_.parent_id as parent5_0_
from
PERSON person0_
Hibernate:
select
person0_.id as id0_,
person0_.name as name0_,
person0_.parent_id as parent5_0_
from
PERSON person0_
org.hibernate.type.NullableType.nullSafeGet(NullableType.java:172) 2008-02-15 14:50:04,796 [main] DEBUG - returning '1' as column: id0_
Exception in thread "main" org.hibernate.InstantiationException: Cannot instantiate abstract class or interface: entity.test.Person
at org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:78)
at org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:100)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.instantiate(AbstractEntityTuplizer.java:351)
at org.hibernate.persister.entity.AbstractEntityPersister.instantiate(AbstractEntityPersister.java:3606)
at org.hibernate.impl.SessionImpl.instantiate(SessionImpl.java:1275)
at org.hibernate.impl.SessionImpl.instantiate(SessionImpl.java:1264)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1299)
at org.hibernate.loader.Loader.getRow(Loader.java:1206)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:580)
at org.hibernate.loader.Loader.doQuery(Loader.java:701)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.doList(Loader.java:2220)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
at org.hibernate.loader.Loader.list(Loader.java:2099)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:378)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:338)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:172)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1121)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
at entity.test.TestInheritance.runQueries(TestInheritance.java:145)
at entity.test.TestInheritance.runTests(TestInheritance.java:119)
at entity.test.TestInheritance.testAnnotationInheritance(TestInheritance.java:177)
at entity.test.TestInheritance.main(TestInheritance.java:191)


Name and version of the database you are using:

Oracle 10g

The generated SQL (show_sql=true):


select
child0_.id as id0_,
child0_.name as name0_,
child0_.parent_id as parent5_0_
from
PERSON child0_

select
person0_.id as id0_,
person0_.name as name0_,
person0_.parent_id as parent5_0_
from
PERSON person0_


Last edited by ericp on Fri Feb 15, 2008 12:43 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 15, 2008 11:12 am 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
I'm just guessing, but I don't thin you need
Code:
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
@org.hibernate.annotations.ForceDiscriminator
@Table(name = "PERSON")


In the child and parent class, since they are already specified in the superclass person. Maybe this is causing the problem.

regards
Jens

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 15, 2008 11:36 am 
Newbie

Joined: Wed Feb 13, 2008 6:01 am
Posts: 8
If I remove the table annotation in the subclasses a new table is created i.e.

create table Parent (
id bigint generated by default as identity (start with 1),
name varchar(255),
job varchar(255),
parent_id bigint,
primary key (id)
)

so that is no good. Maybe another bug?

In addition there are other problems when entities are created with the schema as I posted:

parent.getChildren().add(child);
child.setParent(parent);

session.persist(parent);


insert
into
PERSON
(id, name, parent_id, job, TYPE)
values
(null, ?, ?, ?, 'PARENT')

call identity()

insert
into
PERSON
(id, name, parent_id, TYPE)
values
(null, ?, ?, 'Person')


call identity()

The second sql statement must refer to the child being saved due to some default cascade settings but the type is "Person" which is incorrect. Again, this works just fine with Toplink.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 15, 2008 3:28 pm 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
That is really strange, I just doublechecked on some classes in my current project.

On the Super class there is just

Entity, @Inheritance and @DiscriminatorColumn specified (actually via MappedSuperclass)

The subclasses have only Entity and DiscriminatorValue Anntoations and it works perfect.

On more guess: Are all Entity annotations from the package javax.persistence? this actually should be true vor alle Annotations which also might exist in the org.hibernate.annotation package. Just an idea.

Jens

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 15, 2008 8:15 pm 
Newbie

Joined: Wed Feb 13, 2008 6:01 am
Posts: 8
All the annotations are definitely from javax.... and none are from hibernate except the ones with the fully qualified package name like forced descriminator

It is very strange because I can simply change the provider to toplink and it just works or I can use the hibernate xml mapping and that also works so maybe I am doing something wrong or hibernate is not doing what it should. I can send you the eclipse project fully intact and you can try it yourself if you want. Send me a PM (private message ) with your email if you prefer.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 16, 2008 5:23 am 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
I actually would do that, but I can't find a way to send a PM ... only thing I could find is in the list of users but there doesn't seem to be a search button?

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 16, 2008 9:16 am 
Newbie

Joined: Wed Feb 13, 2008 6:01 am
Posts: 8
you are right, there is no PM facility on this forum.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 20, 2008 2:04 pm 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
I just replied to an email of ericp:

-----

the main problem was the @MappedSuperclass on Person it is just wrong in that place. You should probably almost never have a @Entity and a @MappedSuperClass Annotation on the same Class.

With that annotation gone you need to remove some more annotations from the subclasses. So the class heads look now like this:


Code:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
@org.hibernate.annotations.ForceDiscriminator
@Table(name = "PERSON")
public abstract class Person {


Code:
@Entity
@DiscriminatorValue("PARENT")
public class Parent extends Person {


Code:
@Entity
@DiscriminatorValue("CHILD")
public class Child extends Person {


kind regards
Jens

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
 Post subject: thanks
PostPosted: Thu Feb 21, 2008 5:25 am 
Newbie

Joined: Wed Feb 13, 2008 6:01 am
Posts: 8
That works as expected now. I was suffering from annotation overload it seems. Thank you very much for your help.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 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.