java - español - ¿Necesito elementos de<clase> en persistence.xml?
java orm hibernate (10)
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 @Entity
elementos de <class>
, la aplicación no ve entidades (todas las clases están anotadas con @Entity
).
¿Hay algún mecanismo automático para @Entity
clases @Entity
?
¿Necesito elementos de clase en persistence.xml?
No, no necesariamente. Así es como lo haces en Eclipse (probado por Kepler):
Haga clic con el botón derecho en el proyecto, haga clic en Propiedades , seleccione JPA , en la casilla Administración de clases de persistencia , seleccione Descubrir clases anotadas automáticamente .
En el entorno Java SE, por especificación debe especificar todas las clases como lo ha hecho:
Se debe especificar una lista de todas las clases de persistencia gestionadas nombradas en entornos Java SE para garantizar 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 usar 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 escanea las anotaciones por usted.
Extraoficialmente, puede intentar establecer <exclude-unlisted-classes>false</exclude-unlisted-classes>
en su persistence.xml. Este parámetro se establece de manera predeterminada en false
en EE y true
en SE. Tanto EclipseLink como Toplink admiten hasta donde yo sé. Pero no debe confiar en que funcione en SE, de acuerdo con las especificaciones, como se indicó anteriormente.
Puede INTENTAR lo siguiente (puede o no funcionar 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>
Hibernate no es compatible con <exclude-unlisted-classes>false</exclude-unlisted-classes>
en SE, (otro cartel menciona 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 Importar 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.
No es una solución, sino una pista para quienes usan Spring:
Traté de usar org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
con la configuración persistenceXmlLocation
pero con esto tuve que proporcionar los elementos <class>
(incluso si persistenceXmlLocation
apuntaba a META-INF/persistence.xml
).
Cuando no utilizo persistenceXmlLocation
podría omitir estos elementos de <class>
.
No estoy seguro de que esta solución esté dentro de las especificaciones, pero creo que puedo compartirla con otras.
árbol de dependencia
my-entities.jar
Contiene clases de entidad solamente. No META-INF/persistence.xml
.
my-services.jar
Depende de my-entities
. Contiene EJB solo.
my-resources.jar
Depende de my-services
. Contiene clases de recursos y META-INF/persistence.xml
.
problemas
- ¿Cómo podemos especificar el elemento
<jar-file/>
enmy-resources
como el nombre del artefacto postfixed de una dependencia transitoria? - ¿Cómo podemos sincronizar el valor del elemento
<jar-file/>
y el de la dependencia transitoria real?
solución
dependencia directa (¿redundante?) y filtrado de recursos
Puse una propiedad y una dependencia en 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 prepara persistence.xml
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 regla de dependencyConvergence
convergencia, podemos asegurar que la versión de my-entities
es la misma tanto en directo como transitiva.
<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>
No estoy seguro de si está haciendo algo similar a lo que estoy haciendo, pero estoy generando una carga de Java fuente de 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 el origen de Java y ejecutar Hibernate sobre todas las clases en mi jar de artefacto "base-model" y no especificarlo explícitamente. Estoy agregando "modelo base" como una dependencia para mi componente de hibernación, pero el problema es la etiqueta en persistence.xml solo le permite especificar rutas absolutas.
La forma en que lo solucioné es copiar mi dependencia de jar "modelo base" explícitamente en mi directorio de destino y también quitarle la versión. Entonces, si construyo mi artefacto "base-model", generaré "base-model-1.0-SNAPSHOT.jar", el paso copy-resources lo copiará como "base-model.jar".
Entonces en tu 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 plugin hibernate en la siguiente fase "process-classes":
<!-- 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 contenedor de la siguiente manera:
<jar-file>target/dependency/base-model.jar</jar-file>
y agrega la propiedad:
<property name="hibernate.archive.autodetection" value="class, hbm"/>
Para aquellos que ejecutan JPA en Spring, desde la versión 3.1 en adelante, puede establecer la propiedad packagesToScan
bajo LocalContainerEntityManagerFactoryBean
y deshacerse de persistence.xml por completo.
Persistence.xml tiene un jar-file
que puede usar. 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 llamada OrderManagement
, que utiliza un origen de datos JTA-aware jdbc/MyOrderDB
. El jar-file
y class
elementos de class
especifican clases de persistencia administradas: clases de entidad, clases incrustables y superclases mapeadas. El elemento jar-file
especifica los archivos JAR que son visibles para la unidad de persistencia empaquetada que contiene clases de persistencia administradas, mientras que el elemento de class
nombra explícitamente las clases de persistencia administradas.
En el caso de Hibernate, eche un vistazo al Capítulo2. Configuración y configuración también para más detalles.
EDITAR: en realidad, si no te importa no cumplir con las especificaciones, Hibernate admite la autodetección incluso en Java SE. Para hacerlo, agregue la propiedad hibernate.archive.autodetection
:
<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>
Puede proporcionar la ruta del elemento jar-file
a una carpeta con clases compiladas. Por ejemplo, agregué algo así cuando preparé persistence.xml para algunas pruebas de integración:
<jar-file>file:../target/classes</jar-file>
para JPA 2+ esto hace el truco
<jar-file></jar-file>
escanear todos los frascos en guerra para las clases anotadas @Entity