¿Necesito elementos <class> en persistence.xml?

110

Tengo un archivo persistance.xml muy simple:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
    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">

    <persistence-unit name="eventractor" transaction-type="RESOURCE_LOCAL">
        <class>pl.michalmech.eventractor.domain.User</class>
        <class>pl.michalmech.eventractor.domain.Address</class>
        <class>pl.michalmech.eventractor.domain.City</class>
        <class>pl.michalmech.eventractor.domain.Country</class>

        <properties>
            <property name="hibernate.hbm2ddl.auto" value="validate" />
            <property name="hibernate.show_sql" value="true" />
        </properties>
    </persistence-unit>

</persistence>

y funciona.

Pero cuando elimino <class>elementos, la aplicación no ve entidades (todas las clases están anotadas @Entity).

¿Existe algún mecanismo automático para buscar @Entityclases?

Michał Mech
fuente

Respuestas:

78

Persistence.xml tiene un jar-filearchivo que puede utilizar. Del tutorial de Java EE 5 :

<persistence>
    <persistence-unit name="OrderManagement">
        <description>This unit manages orders and customers.
            It does not rely on any vendor-specific features and can
            therefore be deployed to any persistence provider.
        </description>
        <jta-data-source>jdbc/MyOrderDB</jta-data-source>
        <jar-file>MyOrderApp.jar</jar-file>
        <class>com.widgets.Order</class>
        <class>com.widgets.Customer</class>
    </persistence-unit>
</persistence>

Este archivo define una unidad de persistencia denominada OrderManagement, que utiliza una fuente de datos compatible con JTA jdbc/MyOrderDB. Los elementos jar-filey classespecifican clases de persistencia administradas: clases de entidad, clases incrustables y superclases mapeadas. El jar-fileelemento especifica archivos JAR que son visibles para la unidad de persistencia empaquetada que contiene clases de persistencia administradas, mientras que el classelemento nombra explícitamente clases de persistencia administradas.

En el caso de Hibernate, eche un vistazo al Chapter2. Instalación y configuración también para más detalles.

EDITAR: En realidad, si no le importa no cumplir con las especificaciones, Hibernate admite la detección automática incluso en Java SE. Para hacerlo, agregue la hibernate.archive.autodetectionpropiedad:

<persistence-unit name="eventractor" transaction-type="RESOURCE_LOCAL">
  <!-- This is required to be spec compliant, Hibernate however supports
       auto-detection even in JSE.
  <class>pl.michalmech.eventractor.domain.User</class>
  <class>pl.michalmech.eventractor.domain.Address</class>
  <class>pl.michalmech.eventractor.domain.City</class>
  <class>pl.michalmech.eventractor.domain.Country</class>
   -->

  <properties>
    <!-- Scan for annotated classes and Hibernate mapping XML files -->
    <property name="hibernate.archive.autodetection" value="class, hbm"/>

    <property name="hibernate.hbm2ddl.auto" value="validate" />
    <property name="hibernate.show_sql" value="true" />
  </properties>
</persistence-unit>
Pascal Thivent
fuente
13
Ya veo, pero las entidades (@Entity) están en un proyecto Maven separado, por lo que el nombre del archivo jar puede cambiar en cada compilación. Estoy buscando algo para escanear todo en un paquete específico o classpath. Soy demasiado vago para escribir muchos, muchos elementos <class> en el archivo persistence.xml.
Michał Mech
¡¿En cada construcción ?! Ni siquiera preguntaré por qué, pero ... podrías usar el filtrado para resolver esto.
Pascal Thivent
No todos exactamente, pero quiero resistirme a los cambios.
Michał Mech
5
Hilo antiguo, lo sé, pero eche un vistazo al jpa-maven-plugin .
Laird Nelson
Puede usar el elemento <mapping-file> (que contiene la lista de las entidades) en persistence.xml, para que pueda mantener el mismo nombre de los archivos usados ​​e integrarlos en la compilación de los archivos jar referenciados.
med_alpa
44

En el entorno Java SE, por especificación, debe especificar todas las clases como lo hizo:

Se debe especificar una lista de todas las clases de persistencia administradas con nombre en los entornos Java SE para asegurar la portabilidad.

y

Si no se pretende que las clases de persistencia anotadas contenidas en la raíz de la unidad de persistencia se incluyan en la unidad de persistencia, se debe utilizar el elemento exclude-unlisted-classes. El elemento exclude-unlisted-classes no está diseñado para su uso en entornos Java SE.

(JSR-000220 6.2.1.6)

En entornos Java EE, no tiene que hacer esto ya que el proveedor busca anotaciones por usted.

Extraoficialmente, puede intentar configurar <exclude-unlisted-classes>false</exclude-unlisted-classes>su persistence.xml. Este parámetro está predeterminado falseen EE y trueen SE. Tanto EclipseLink como Toplink admiten esto, por lo que puedo decir. Pero no debe confiar en que funcione en SE, de acuerdo con las especificaciones, como se indicó anteriormente.

Puede PROBAR lo siguiente (puede que funcione o no en entornos SE):

<persistence-unit name="eventractor" transaction-type="RESOURCE_LOCAL">
     <exclude-unlisted-classes>false</exclude-unlisted-classes>

    <properties>
            <property name="hibernate.hbm2ddl.auto" value="validate" />
            <property name="hibernate.show_sql" value="true" />
    </properties>
</persistence-unit>
Mads Mobæk
fuente
2
<exclude-unlisted-classes>false</exclude-unlisted-classes>no funcionó con WildFly 8.2.1.Final + Hibernate 4.3.7
Andreas Dietrich
12

¿Necesito elementos de clase en persistence.xml?

No, no necesariamente. Así es como se hace en Eclipse (probado por Kepler):

Haga clic derecho en el proyecto, haga clic en Propiedades , seleccione JPA , en la gestión de clases de persistencia marque Descubrir clases anotadas automáticamente .

ingrese la descripción de la imagen aquí

abbas
fuente
9
¿Por qué votar a favor? OP ni siquiera menciona Eclipse y esta respuesta no muestra lo que hace esta función de Eclipse debajo del capó para que uno pueda hacer eso sin un IDE.
Artem Novikov
2
@Artem Novikov: Encuentro esto muy duro ya que a menudo la pregunta surge de diferentes entornos y aquí queremos ayudar o dar pistas que sean útiles. (como para mí) Es útil ya que Eclipse es un IDE común para desarrollar como este y bajo el capó no es tan importante, pero supongo que incluirá todos los proyectos de espacio de trabajo relevantes (por ejemplo, mi proyecto depende de).
Andreas Dietrich
stackoverflow.com/questions/17951297/… Buen truco, pero aparentemente solo funciona si las entidades terminan en el mismo cargador de clases que persistence.xml
Pierluigi Vernetto
@abbas Muestra el persistence.xmlque genera Eclipse.
Frans
12

Para aquellos que ejecutan JPA en Spring, a partir de la versión 3.1, puede establecer la packagesToScanpropiedad enLocalContainerEntityManagerFactoryBean y deshacerse de persistence.xml por completo.

Aquí está la verdad

Christopher Yang
fuente
¡Trabajó para mi! El escenario era Spring 4 + hibernate + jpa2 + maven. Las pruebas de JUnit no encontraron mis entidades, pero con esta configuración hizo el trabajo.
Sábado
8

Puede proporcionar la jar-fileruta del elemento a una carpeta con clases compiladas. Por ejemplo, agregué algo así cuando preparé persistence.xml a algunas pruebas de integración:

 <jar-file>file:../target/classes</jar-file>
Arek Trzepacz
fuente
¡Esto es lo que estaba buscando!
xtian
¡También funciona con EclipseLink!
Bombe
8

para JPA 2+ esto funciona

 <jar-file></jar-file>

escanee todos los frascos en la guerra en busca de clases @Entity anotadas

eriskooo
fuente
2
¿tienes más información sobre esto? ¿Funciona esto por accidente o está escrito en la especificación? ¿Depende de la implementación?
Markus
el escáner está en la clase extendiendo AbstractScannerImpl, hibernate - no
tengo
1
En Java SE con Hibernate 5.1.2.Final, esta solución no funciona. Hibernate espera un nombre de archivo jar ( java.lang.IllegalArgumentException: Unable to visit JAR file:).
Stephan
1
¡trabajos! :) con WildFly 8.2.1.Final + Hibernate 4.3.7.Final
Andreas Dietrich
Thx man, busqué mucho y esta es la mejor solución disponible. Wildfly10 + Hibernate 5.0.7 funcionando.
sobre el
7

Hibernate no es compatible <exclude-unlisted-classes>false</exclude-unlisted-classes>con SE (otro póster mencionó que esto funciona con TopLink y EclipseLink).

Hay herramientas que generarán automáticamente la lista de clases en persistence.xml, por ejemplo, el asistente de importación de esquema de base de datos en IntelliJ. Una vez que tenga las clases iniciales de su proyecto en persistence.xml, debería ser simple agregar / eliminar clases individuales a mano a medida que avanza su proyecto.

Chuck Stephanski
fuente
La detección automática de entidades en Java SE simplemente no es parte de JPA. Las aplicaciones que se basan en esto no son portátiles.
Pascal Thivent
4

No estoy seguro de si está haciendo algo similar a lo que estoy haciendo, pero estoy generando una carga de fuente Java desde un XSD usando JAXB en un componente separado usando Maven. Digamos que este artefacto se llama "modelo base"

Quería importar este artefacto que contiene la fuente de Java y ejecutar hibernate sobre todas las clases en mi jar de artefacto "modelo base" y no especificar cada uno explícitamente. Estoy agregando "modelo base" como una dependencia para mi componente de hibernación, pero el problema es que la etiqueta en persistence.xml solo le permite especificar rutas absolutas.

La forma en que lo resolví es copiar mi dependencia de jar del "modelo base" explícitamente en mi directorio de destino y también eliminar la versión de la misma. Entonces, mientras que si construyo mi artefacto "modelo base", genera "modelo base-1.0-SNAPSHOT.jar", el paso de copia de recursos lo copia como "modelo base.jar".

Entonces, en su pom para el componente de hibernación:

            <!-- We want to copy across all our artifacts containing java code
        generated from our scheams. We copy them across and strip the version
        so that our persistence.xml can reference them directly in the tag
        <jar-file>target/dependency/${artifactId}.jar</jar-file> -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.5.1</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                </execution>
            </executions>       
            <configuration>
                <includeArtifactIds>base-model</includeArtifactIds>
                <stripVersion>true</stripVersion>
            </configuration>        
        </plugin>

Luego llamo al complemento de hibernación en la siguiente fase "clases de proceso":

            <!-- Generate the schema DDL -->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>hibernate3-maven-plugin</artifactId>
            <version>2.2</version>

            <executions>
                <execution>
                    <id>generate-ddl</id>
                    <phase>process-classes</phase>
                    <goals>
                        <goal>hbm2ddl</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <components>
                    <component>
                        <name>hbm2java</name>
                        <implementation>annotationconfiguration</implementation>
                        <outputDirectory>/src/main/java</outputDirectory>
                    </component>
                </components>
                <componentProperties>
                    <persistenceunit>mysql</persistenceunit>
                    <implementation>jpaconfiguration</implementation>
                    <create>true</create>
                    <export>false</export>
                    <drop>true</drop>
                    <outputfilename>mysql-schema.sql</outputfilename>
                </componentProperties>
            </configuration>
        </plugin>

y finalmente en mi persistence.xml puedo establecer explícitamente la ubicación del frasco así:

<jar-file>target/dependency/base-model.jar</jar-file>

y agregue la propiedad:

<property name="hibernate.archive.autodetection" value="class, hbm"/>
Spencer Loveridge
fuente
3

No es una solución, sino una pista para aquellos que usan Spring:

Traté de usar org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeancon la configuración, persistenceXmlLocationpero con esto tuve que proporcionar los <class>elementos (incluso si el persistenceXmlLocationsolo apuntaba aMETA-INF/persistence.xml ).

Cuando no los use persistenceXmlLocation, podría omitir estos <class>elementos.

Ethan Leroy
fuente
Usé persistenceXmlLocationpropiedad en mi LocalContainerEntityManagerFactoryBeanconfiguración. Pero todas las consultas funcionan incluso si omito los <class>elementos. Está en una aplicación Spring / Hibernate / Maven. Pero en su sugerencia dice que "Cuando no use persistenceXmlLocation, podría omitir estos elementos <class>". pero es al revés para mí.
Lucky
@Ethan, tienes razón, porque persistenceXmlLocation anula packagesToScan, si miras en las fuentes. Así que no lo use cuando use packagesToScan.
Artem Novikov
2

No estoy seguro de que esta solución esté bajo las especificaciones, pero creo que puedo compartirla con otros.

árbol de dependencia

mis-entidades.jar

Solo contiene clases de entidad. NoMETA-INF/persistence.xml .

my-services.jar

Depende de my-entities. Solo contiene EJB.

my-resources.jar

Depende de my-services. Contiene clases de recursos y META-INF/persistence.xml.

problemas

  • ¿Cómo podemos especificar el <jar-file/>elemento en my-resourcescomo el nombre de artefacto posfijado en la versión de una dependencia transitoria?
  • ¿Cómo podemos sincronizar el <jar-file/>valor del elemento y el de la dependencia transitoria real?

solución

dependencia directa (¿redundante?) y filtrado de recursos

Pongo una propiedad y una dependencia my-resources/pom.xml.

<properties>
  <my-entities.version>x.y.z-SNAPSHOT</my-entities.version>
</properties>
<dependencies>
  <dependency>
    <!-- this is actually a transitive dependency -->
    <groupId>...</groupId>
    <artifactId>my-entities</artifactId>
    <version>${my-entities.version}</version>
    <scope>compile</scope> <!-- other values won't work -->
  </dependency>
  <dependency>
    <groupId>...</groupId>
    <artifactId>my-services</artifactId>
    <version>some.very.sepecific</version>
    <scope>compile</scope>
  </dependency>
<dependencies>

Ahora persistence.xmlprepárate para ser filtrado

<?xml version="1.0" encoding="UTF-8"?>
<persistence ...>
  <persistence-unit name="myPU" transaction-type="JTA">
    ...
    <jar-file>lib/my-entities-${my-entities.version}.jar</jar-file>
    ...
  </persistence-unit>
</persistence>

Complemento Maven Enforcer

Con la dependencyConvergenceregla, podemos asegurar que la my-entities'versión es la misma tanto en directo como en transitivo.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>1.4.1</version>
  <executions>
    <execution>
      <id>enforce</id>
      <configuration>
        <rules>
           <dependencyConvergence/>
        </rules>
      </configuration>
      <goals>
        <goal>enforce</goal>
      </goals>
    </execution>
  </executions>
</plugin>
Jin Kwon
fuente
0

No necesariamente en todos los casos.

Estoy usando Jboss 7.0.8 y Eclipselink 2.7.0. En mi caso, para cargar entidades sin agregar las mismas en persistence.xml, agregué la siguiente propiedad del sistema en Jboss Standalone XML:

<property name="eclipselink.archive.factory" value="org.jipijapa.eclipselink.JBossArchiveFactoryImpl"/>

Gandhi
fuente