Thursday, February 17, 2011

I hate Java #1: org.hibernate.MappingException: Unknown entity

Well, as you might know I started learning/coding Java because I will kinda be working in production and as you might know in my first month in Java I got the idea to write a book about it. Here is how the cover would look.

image

Anyway this is not the point of this particular post. So let’s see what we got. We got a very unusual exception: org.hibernate.MappingException: Unknown entity.

We tried to use annotated hibernate entities, everything seemed to be nice configured in hibernate.xml but it didn’t worked. Our Hibernate should work with Spring. So I’ll put some XML’s and classes before and than I’ll tell you the solution

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <!-- Hibernate session factory -->


    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="jdbc:postgresql://localhost:5432/testh" />
        <property name="username" value="postgres" />
        <property name="password" value="postgres" />
    </bean>


    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="entity" />
        
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <tx:annotation-driven />

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!-- The Spring support for Hibernate calls -->
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
</beans>

 

The property “packagesToScan” is used to indicate where the hibernate annotation entities are.

Now the entity java class was like this

package entity;

import java.io.Serializable;
import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Entity;

@Entity
@Table(name = "emp", schema = "public")
public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "emp_userid")
    private String id;

    @Column(name = "emp_link_date")
    private Timestamp date;

    @Column(name = "emp_logdel")
    private boolean logicalDelete;

    @Column(name = "emp_name")
    private String name;

    @Column(name = "employee_surname")
    private String surname;

    public Employee() {
        // TODO Auto-generated constructor stub
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Timestamp getDate() {
        return date;
    }

    public void setDate(Timestamp date) {
        this.date = date;
    }

    public boolean getLogicalDelete() {
        return logicalDelete;
    }

    public void setLogicalDelete(boolean logicalDelete) {
        this.logicalDelete = logicalDelete;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public boolean isLogicalDelete() {
        return logicalDelete;
    }

}

Well I got this error which was kind of stupid:

org.hibernate.MappingException: Unknown entity: entity.Employee
    at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:597)
    at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:68)
    at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:879)
    at org.hibernate.impl.SessionImpl.get(SessionImpl.java:816)
    at org.hibernate.impl.SessionImpl.get(SessionImpl.java:809)
    at com.givaudan.persistence.UserDaoBean.getUserById(UserDaoBean.java:12)
    at com.givaudan.masterdata.service.UserRightsServiceBean.getUserById(UserRightsServiceBean.java:12)
    at service.UserRightsServiceTest.testGetUserById(UserRightsServiceTest.java:28)
    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:597)
    at org.springframework.test.context.junit4.SpringTestMethod.invoke(SpringTestMethod.java:160)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTestMethod(SpringMethodRoadie.java:233)
    at org.springframework.test.context.junit4.SpringMethodRoadie$RunBeforesThenTestThenAfters.run(SpringMethodRoadie.java:333)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:217)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:197)
    at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:143)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:160)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    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)

And I got to this blog post on the net. http://thejavablog.wordpress.com/2008/05/21/orghibernatemappingexception-unknown-entity/

Now that explained everything: I shoudn’t use org.hibernate.annotations.Entity, but  javax.persistence.Entity.

Isn’t that sweet ? For a newbie in Java it’s really hard to understand why Entity annotation which you do use at hibernate, shouldn’t be in org.hibernate.annotations.Entity, but instead in javax.persistence.Entity.

Well looks like java API coders don’t like logical and simple things. And another question when I should use org.hibernate.annotations.Entity? Do I really need it with the same name in this package?

Well may be someone on the Java side would explain this thing. That really would be nice.

4 comments:

  1. Hello Timur

    > Entity annotation which you do use at
    >hibernate, shouldn’t be in
    >org.hibernate.annotations.Entity, but instead in
    >javax.persistence.Entity.

    This is because by putting the Entity in the javax.persistence package you abstract the entity level. You can take any other persistence framework that implements the specification (like TopLink (now EclipseLink), OpenJPA, JPOX (now DataNucleus) etc) and use it instead of hibernate, and without having to change the code a bit. So if later you are not happy with Hibernate and you want to change, you don't change the code and recompile, you just change the jar files.

    > And another question when I should use
    >org.hibernate.annotations.Entity? Do I really
    >need it with the same name in this package?

    You use the org.hibernate.annotations.Entity if you want to define additional information (metadata) that are not defined in the standard javax.persistence.Entity, like dynamic insert, dynamic update, etc. But by doing this you tie your code to Hibernate, since other JPA implementation do not have the org.hibernate.annotations.Entity package (they might have their own ones though).

    Hope it helps.

    ReplyDelete
  2. wow, just had the same problem. Unbelievable, but thanks for the fix.

    ReplyDelete
  3. The org.hibernate.annotations existed before JPA1/2. JPA now exists and for new projects, you probably want to use it's annotations (though annoyingly they are often subtly different).

    Now the JPA folks could have used new names (and they did in some cases), but the hibernate annotations (4 years old before JPA1 came out) were logical names. Hence the problem

    This has not a thing to do with JAVA. It has to do with the strengths and weaknesses of a platform where many things get standardized and pulled from 3rd parties (the xml parser, ws, servlet technology, hibernate, etc).

    ReplyDelete
  4. Even though I have correct package javax.persistence.Entity but I am facing similar issue . More surprisingly same code is working in Eclipse but when I am deploying JAR in unix I am facing this issue.

    I have using Spring + Hibernate.

    Dont know what could be problem .







    ReplyDelete