javahibernatesqljdbc

org.hibernate.MappingException: Unknown entity Main$1


I am new to hibernate. I am trying to generate database tables from annotated entity classes.

Tag class:

package playground.data.entities;

import java.time.Instant;
import javax.persistence.*;

@Entity
public class Tag extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long Id;

    @Column(unique = true, nullable = false)
    public String Name;

    @Column(nullable = false)
    public Instant CreatedOn;
}

Here is my hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
        <property name="hibernate.connection.password">1234</property>
        <property name="hibernate.connection.url">jdbc:sqlserver://localhost;database=HibernatePlayground;SelectMethod=cursor</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.default_schema">dbo</property>
        <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
    
        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <mapping class="playground.data.entities.Tag" />
    </session-factory>
</hibernate-configuration>

Here is my HibernateUtil class (reference: http://www.mkyong.com/hibernate/maven-3-hibernate-3-6-oracle-11g-example-xml-mapping/, http://www.mkyong.com/hibernate/maven-3-hibernate-3-6-oracle-11g-example-annotation/):

package util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

import playground.data.entities.Tag;

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            Configuration config = new Configuration();
            //config.addAnnotatedClass(Tag.class); //<-- tried this too
            return config.configure().buildSessionFactory();

            // Also tried the following.
            // ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();

            // return new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();

        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        // Close caches and connection pools
        getSessionFactory().close();
    }

}

Lastly, using these from Main:

package playground;

import java.time.Instant;

import org.hibernate.Session;

import playground.data.entities.Tag;
import util.HibernateUtil;

public class Main {

    public static void main(String[] args) {
    
        Tag tag1 = new Tag() {
            {
                Name = "Tag1";
                CreatedOn = Instant.now();
            }
        };
        Tag tag2 = new Tag(){
            {
                Name = "Tag2";
                CreatedOn = Instant.now();
            }
        };
        Session ss = HibernateUtil.getSessionFactory().openSession();
        ss.beginTransaction();
        // saving objects to session
        ss.save(tag1); //<-- getting error here.
        ss.save(tag2);
        ss.getTransaction().commit();
        HibernateUtil.shutdown();
    }
}

But while saveing tag1 object, I am getting Exception in thread "main" org.hibernate.MappingException: Unknown entity: playground.Main$1. Below is the full stack trace along with logged info from hibernate:


Nov 15, 2016 11:42:59 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.2.4.Final}
Nov 15, 2016 11:42:59 AM org.hibernate.cfg.Environment 
INFO: HHH000206: hibernate.properties not found
Nov 15, 2016 11:42:59 AM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Nov 15, 2016 11:43:00 AM org.hibernate.annotations.common.reflection.java.JavaReflectionManager 
INFO: HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
Nov 15, 2016 11:43:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
Nov 15, 2016 11:43:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [com.microsoft.sqlserver.jdbc.SQLServerDriver] at URL [jdbc:sqlserver://localhost;database=HibernatePlayground;SelectMethod=cursor]
Nov 15, 2016 11:43:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=sa, password=****}
Nov 15, 2016 11:43:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Nov 15, 2016 11:43:00 AM org.hibernate.engine.jdbc.connections.internal.PooledConnections 
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
Nov 15, 2016 11:43:00 AM org.hibernate.dialect.Dialect 
INFO: HHH000400: Using dialect: org.hibernate.dialect.SQLServerDialect
Nov 15, 2016 11:43:02 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@10c626be] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Exception in thread "main" org.hibernate.MappingException: Unknown entity: playground.Main$1
    at org.hibernate.metamodel.internal.MetamodelImpl.entityPersister(MetamodelImpl.java:620)
    at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1605)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:104)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
    at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
    at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:674)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:666)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:661)
    at playground.Main.main(Main.java:85)

I am using:

My project structure is as follows:

project structure

I am not sure why it is throwing MappingException for the Main. Please suggest.


Solution

  • When you do the following, you are creating an anonymous subclass of the entity class Tag with an instance initializer to initialize the member variables. This is not the correct way to create and initialize a Tag entity:

    Tag tag1 = new Tag() {
        {
            Name = "Tag1";
            CreatedOn = Instant.now();
        }
    };
    

    Instead, create an instance of class Tag itself and set the values:

    Tag tag1 = new Tag();
    tag1.Name = "Tag1";
    tag1.CreatedOn = Instant.now();
    

    But there's more wrong with this code. The fields in class Tag should not be public, but private, and you should add getter and setter methods to class Tag. Also, field names in Java conventionally should have names that start with a lower-case letter.

    @Entity
    public class Tag extends BaseEntity {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private long id;
    
        @Column(unique = true, nullable = false)
        private String name;
    
        @Column(nullable = false)
        private Instant createdOn;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Instant getCreatedOn() {
            return createdOn;
        }
    
        public void setCreatedOn(Instant createdOn) {
            this.createdOn = createdOn;
        }
    }
    

    And to initialize it:

    Tag tag1 = new Tag();
    tag1.setName("Tag1");
    tag1.setCreatedOn(Instant.now());