Как автоматически регистрировать объекты с JPA/Hibernate: неизвестный объект

Я столкнулся с проблемой конфигурации Hibernate/JPA, которая предотвращает автоматическую регистрацию моих аннотированных объектов JPA:

java.lang.IllegalArgumentException: Unknown entity: com.example.crm.server.model.Language
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:671)
    at com.example.crm.server.model.Language.persist(Language.java:64)
    at com.example.crm.server.LanguageTest.testPersistAndRemove(LanguageTest.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

В моем классе сущности я:

@Entity
@Table(name="Languages")
public class Language implements Serializable
{
    @Id
    private Long id;
    private String name;
    // etc...
}

И в MySQL таблица "Языки" выглядит так:

+-------------+----------+------+-----+---------+-------+
| Field       | Type     | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+-------+
| Language_ID | int(11)  | NO   | PRI | NULL    |       | 
| Name        | char(18) | YES  |     | NULL    |       | 
+-------------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

И мой persistence.xml выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">

    <persistence-unit name="crm">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost/crm"/>
            <property name="hibernate.connection.username" value="crmuser"/>
            <property name="hibernate.connection.password" value="mypass"/>
            <property name="hibernate.c3p0.min_size" value="5"/>
            <property name="hibernate.c3p0.max_size" value="20"/>
            <property name="hibernate.c3p0.idleTestPeriod" value="30"/>
            <property name="hibernate.c3p0.timeout" value="0"/>
            <property name="hibernate.c3p0.max_statements" value="0"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.query.jpaql_strict_compliance" value="false"/>
            <property name="hibernate.validator.apply_to_ddl" value="false"/>
            <property name="hibernate.validator.autoregister_listeners" value="false"/>
            <property name="hibernate.archive.autodetection" value="class, hbm"/>
            <property name="hibernate.hbm2ddl.auto" value="create"/>
        </properties>
    </persistence-unit>

</persistence>

EDIT: здесь, как я получаю свой EntityManager и сохраняюсь:

public void persist()
{
    EntityManager em = entityManager();
    try
    {
        em.getTransaction().begin();
        em.persist(this);
        em.getTransaction().commit();
    }
    finally
    {
        em.close();
    }
}

public static EntityManager entityManager()
{
    return EMF.get().createEntityManager();
}

Ответ 1

Это оказалось довольно простым: перечислить классы непосредственно в файле persistence.xml. И armandino, и MikelRascher привели меня к этому ответу, хотя и косвенно, так что он реквизит к ним.

Вот файл persistence.xml, который я использую сейчас:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">

    <persistence-unit name="crm">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <class>com.example.Language</class>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost/crm"/>
            <property name="hibernate.connection.username" value="myuser"/>
            <property name="hibernate.connection.password" value="mypass"/>
            <property name="hibernate.c3p0.min_size" value="5"/>
            <property name="hibernate.c3p0.max_size" value="20"/>
            <property name="hibernate.c3p0.idleTestPeriod" value="30"/>
            <property name="hibernate.c3p0.timeout" value="0"/>
            <property name="hibernate.c3p0.max_statements" value="0"/>
            <!--property name="hibernate.show_sql" value="true"/>-->
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.query.jpaql_strict_compliance" value="false"/>
            <property name="hibernate.validator.apply_to_ddl" value="false"/>
            <property name="hibernate.validator.autoregister_listeners" value="false"/>
            <property name="hibernate.archive.autodetection" value="class, hbm"/>
            <property name="hibernate.hbm2ddl.auto" value="create"/>
        </properties>
    </persistence-unit>

</persistence>

Ответ 2

Обновление

Здесь более JPA-подобный подход:

Ejb3Configuration ejb3Configuration = new Ejb3Configuration();
ejb3Configuration.addResource("META-INF/orm.xml");
ejb3Configuration.configure("persistence.xml");

EntityManagerFactory factory = ejb3Configuration.buildEntityManagerFactory();
EntityManager em = factory.createEntityManager();

И orm.xml должен выглядеть примерно так:

<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
    version="1.0">
    <package>org.example</package>
    <entity class="org.example.MyEntity"/>
    <entity class="org.example.AnotherEntity"/>
</entity-mappings>

Ответ 3

Как вы создаете менеджера сущностей?

Вы должны посмотреть сообщения log4j уровня INFO из спящего режима, установив это в log4j.properties:

# Hibernate logging options (INFO only shows startup messages)
log4j.logger.org.hibernate=INFO

# Log JDBC bind parameter runtime arguments
log4j.logger.org.hibernate.type=INFO

Вы должны увидеть свой класс в сообщениях:

15:39:37,519  INFO Version:156 - Hibernate Commons Annotations 3.2.0.Final
15:39:37,527  INFO Environment:148 - Hibernate 3.6.0.Final
15:39:37,529  INFO Environment:148 - hibernate.properties not found
15:39:37,532  INFO Environment:148 - Bytecode provider name : javassist
15:39:37,535  INFO Environment:148 - using JDK 1.4 java.sql.Timestamp handling
15:39:37,588  INFO Version:156 - Hibernate EntityManager 3.6.0.Final
15:39:38,036  INFO AnnotationBinder:156 - Binding entity from annotated class: com.example.crm.server.model.Language

Перейдите к DEBUG, если вам нужна дополнительная информация.

также Вы не указываете имя своей единицы персистентности при создании диспетчера сущностей. Может быть, это не важно:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("crm");
EntityManager em = emf.createEntityManager();