Spring 3.1 Hibernate 4 exception for Inheritance [cannot be cast to org.hibernate.mapping.RootClass]
Asked Answered
E

4

43

Hi I have just started using Spring , with Hibernate4 and maven. Basically my class hierarchy is HUmanMicroTask extends from MicroTask . In future there may be several other classes extending from MicroTask. I was trying to have a one table per concrete class which is the simplest way to get up and running with spring3 and hibernate 4. However when i run my code. I keep getting the following exception

13:11:52,260 ERROR TestContextManager:324 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@6ef137d] to prepare test instance [HumanMicroTaskBaseHibernateTest@52c05d3b]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [database-config.xml]: Invocation of init method failed; nested exception is java.lang.ClassCastException: org.hibernate.mapping.UnionSubclass cannot be cast to org.hibernate.mapping.RootClass
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:567)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
    at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228)
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
    ... 24 more
Caused by: java.lang.ClassCastException: org.hibernate.mapping.UnionSubclass cannot be cast to org.hibernate.mapping.RootClass
    at org.hibernate.cfg.annotations.PropertyBinder.bind(PropertyBinder.java:212)
    at org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:203)
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2013)
    at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:768)
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:687)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3431)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3385)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1337)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1727)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1778)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:184)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:314)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
    ... 38 more

Although I have seen quite a few forums, I am unabelt o decide on where I am making the mistake. My MicroTask class looks as follows :

@Entity
@Table(name = "MICROTASK")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class MicroTask {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "MICROTASKID")
    private String microTaskId;
    @Column(name = "CREATIONDATE")
    private Date creationDate;
    @Column(name = "DESCRIPTION")
    private String description;

    public Date getCreationDate() {
        return creationDate;
    }
//More Getters and setters 

My HumanMicroTask Class looks as follows :

    @Entity
    @Table(name = "HUMANMICROTASK")
    @AttributeOverrides({
        @AttributeOverride(name="microTaskId", column=@Column(name="MICROTASKID")),
        @AttributeOverride(name="creationDate", column=@Column(name="CREATIONDATE")),
        @AttributeOverride(name="description", column=@Column(name="DESCRIPTION"))
    })
    public class HumanMicroTask extends MicroTask {


        @Column(name = "TITLE")
        private String title;
        @Column(name = "CHANNEL")
        private String channel;
        @Id
        @Column(name = "HMTID")
        private String humanMicroTaskid;

        public String getId() {
            return humanMicroTaskid;
        }
//More Getters and setters

And my config.xml looks as follows :

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        ">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass">
            <value>${jdbc.driver.className}</value>
        </property>
        <property name="jdbcUrl">
            <value>${jdbc.url}</value>
        </property>
        <property name="user">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>

    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref bean="dataSource"/>
        </property>
        <property name="packagesToScan" value="com.hp.hpl.crowdcloud" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${jdbc.hibernate.dialect}</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
                <!-- uncomment this for first time run -->
                <prop key="hibernate.hbm2ddl.auto">create</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
    </bean>
    <tx:annotation-driven />

</beans>

My Maven Configuration

    <maven.test.failure.ignore>true</maven.test.failure.ignore>
    <org.springframework.version>3.1.0.RELEASE</org.springframework.version>
    <hibernate.version>4.1.1.Final</hibernate.version>
    <sl4j.version>1.5.6</sl4j.version>

Kindly help me out. I am not sure where I making the mistake.

Embolic answered 23/8, 2012 at 7:48 Comment(1)
possible duplicate #3155149Lifton
L
80

It is due to Id column in both classes. Remove the Id from HumanMicroTask.

Leifeste answered 23/8, 2012 at 8:16 Comment(7)
You needn't delete that part of the code from the question, now it's all incomprehensible.Oenone
Worked! Thank you. Why the error message isn't as suggestive as yours?Advice
Removing the @Id annotation from subclasses is enough, or you can also probably delete the field, getters and setters, because the inheritance strategy InheritanceType.TABLE_PER_CLASS requires you to use all the inherited columns in subclass table with exactly the same column names, so mapping can be inherited from super classes. Other inheritance strategies may require you to use different ID column name for each subentity, hence @Id mapping can't be inherited to subclasses and is declared explicitly.Tallboy
This is old, you may not answer, but what if my subclass table also has an identity column?Pejorative
@Pejorative why would you like to keep Id in the subclass?Leifeste
@Leifeste Well, its their own identity column if I remember what I meant when I wrote that. Either way I sorted it out with being a little more explicit with my annotationsPejorative
@Pejorative could you expand on "being a little more explicit with my annotations"? I think I'm having the same problem, as I need to have my own identity in a subclass but I don't have a solution yet.Koroseal
A
11

to fix this Remove @Id from Subclass

in MicroTask keep

   @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "MICROTASKID")
    private String microTaskId;

in Subclass HumanMicroTask remove

   @Id
    @Column(name = "HMTID")
    private String humanMicroTaskid;
Animal answered 15/6, 2013 at 19:27 Comment(0)
S
9

I had the same problem some time ago, since your parent class has a primary key: 'Id', when the subclasses are generated they automatically generate a foreign key with the exact name of their parent's primary key

Example: (Pseudocode)

Entity Definition

Parent Class

  @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    @Table(name = "abstract_person", catalog = "catalog", schema = "")
    class AbstractPerson{

        //Primary Key
        @Id
        @Column(name = "idPerson")
        int idPerson;

        @Basic
        @Column(name = "name")
        String name;

        //corresponding getters and setters
    }

Child Class:

 @Entity
    @Table(name = "concrete_person", catalog = "catalog", schema = "")
    class ConcretePerson extends AbstractPerson{

       //No id or primary key is defined here

        @Basic
        @Column(name="profession")
        String profession;

    }

Table Generation

Parent class will map to this

Table "abstract_person"
id: Int (primary key)
name: Varchar

Child class will map to this:


Table "concrete_person"
profession: Varchar
idPerson: int (Automatically generated, foreign key to parent table and primary class of this table)

//Assumptions
Mysql database;
Jpa 2 Hibernate Implementation;
NetBeans 7x Ide

Septuagenarian answered 15/3, 2014 at 14:40 Comment(0)
B
0

For TABLE_PER_CLASS hierarchy, the child class inherit the unique key from the parent and so we should not mention unique key constraint in child entity.

Remove the primary key annotations and this worked well for me.

Bligh answered 16/4, 2020 at 8:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.