Ho bisogno di elementi <class> in persistence.xml?


110

Ho un file persistance.xml molto semplice:

<?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>

e funziona.

Ma quando rimuovo gli <class>elementi l'applicazione non vede le entità (tutte le classi sono annotate con @Entity).

Esiste un meccanismo automatico per la scansione delle @Entityclassi?

Risposte:


78

Persistence.xml ha un jar-fileche puoi usare. Dal tutorial 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>

Questo file definisce un'unità di persistenza denominata OrderManagement, che utilizza un'origine dati compatibile con JTA jdbc/MyOrderDB. Gli elementi jar-filee classspecificano le classi di persistenza gestite: classi di entità, classi incorporabili e superclassi mappate. L' jar-fileelemento specifica i file JAR che sono visibili all'unità di persistenza pacchettizzata che contengono classi di persistenza gestite, mentre l' classelemento denomina esplicitamente le classi di persistenza gestite.

Nel caso di Hibernate, dai un'occhiata al Capitolo2. Installazione e configurazione anche per maggiori dettagli.

EDIT: In realtà, se non ti dispiace non essere conforme alle specifiche, Hibernate supporta il rilevamento automatico anche in Java SE. Per fare ciò, aggiungi la hibernate.archive.autodetectionproprietà:

<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>

13
Capisco, ma le entità (@Entity) sono in un progetto Maven separato, quindi il nome del file jar può cambiare ad ogni build. Sto cercando qualcosa per scansionare tutto in un pacchetto o un classpath specifico. Sono solo troppo pigro per digitare molti, molti elementi <class> nel file persistence.xml.
Michał Mech,

Su ogni build ?! Non ti chiederò nemmeno perché ma ... potresti usare il filtro per risolvere questo problema.
Pascal Thivent

Non tutti esattamente, ma voglio essere resistente ai cambiamenti.
Michał Mech,

5
Discussione antica, lo so, ma dai un'occhiata al plugin jpa-maven .
Laird Nelson,

È possibile utilizzare l'elemento <mapping-file> (che contiene l'elenco delle entità) in persistence.xml, in modo da poter mantenere lo stesso nome dei file utilizzati e integrarli nella build dei jar referenziati.
med_alpa

44

In ambiente Java SE, per specifica devi specificare tutte le classi come hai fatto:

Un elenco di tutte le classi di persistenza gestite denominate deve essere specificato negli ambienti Java SE per assicurare la portabilità

e

Se non si intende che le classi di persistenza annotate contenute nella radice dell'unità di persistenza siano incluse nell'unità di persistenza, dovrebbe essere usato l'elemento exclude-unlisted-classes. L'elemento exclude-unlisted-classes non è destinato all'uso in ambienti Java SE.

(JSR-000220 6.2.1.6)

Negli ambienti Java EE, non è necessario eseguire questa operazione poiché il provider esegue la scansione delle annotazioni per te.

Non ufficialmente, puoi provare a impostare <exclude-unlisted-classes>false</exclude-unlisted-classes>nel tuo persistence.xml. Il valore predefinito di questo parametro è falsein EE e truein SE. Sia EclipseLink che Toplink lo supportano per quanto ne so. Ma non dovresti fare affidamento sul fatto che funzioni in SE, secondo le specifiche, come indicato sopra.

Puoi PROVARE quanto segue (può o non può funzionare in ambienti 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>

2
<exclude-unlisted-classes>false</exclude-unlisted-classes>non ha funzionato con WildFly 8.2.1 Finale + Hibernate 4.3.7
Andreas Dietrich

12

Ho bisogno di elementi Class in persistence.xml?

No, non necessariamente. Ecco come lo fai in Eclipse (testato da Kepler):

Fare clic con il tasto destro sul progetto, fare clic su Proprietà , selezionare JPA , nella gestione delle classi di persistenza spuntare Scopri automaticamente le classi annotate .

inserisci qui la descrizione dell'immagine


9
Perché votare a favore? OP non menziona nemmeno Eclipse e questa risposta non mostra cosa fa questa funzione Eclipse sotto il cofano in modo che si possa farlo senza un IDE.
Artem Novikov

2
@Artem Novikov: lo trovo duro poiché spesso la domanda nasce da ambienti diversi e qui vogliamo aiutare o dare suggerimenti utili! (come per me) È utile poiché Eclipse è un IDE comune per lo sviluppo in questo modo e sotto il cofano non è così importante, ma immagino che includerà tutti i progetti rilevanti dell'area di lavoro (ad esempio il mio progetto dipende da).
Andreas Dietrich

stackoverflow.com/questions/17951297/… bel trucco, ma a quanto pare funziona solo se le entità finiscono nello stesso classloader del persistence.xml
Pierluigi Vernetto

@abbas Per favore mostra il persistence.xmlche Eclipse genera.
Frans

12

Per coloro che eseguono JPA in primavera, dalla versione 3.1 in poi, è possibile impostare la packagesToScanproprietà in LocalContainerEntityManagerFactoryBeaned eliminare del tutto persistence.xml.

Ecco il minimo


Ha funzionato per me! Lo scenario era la primavera 4 + ibernazione + jpa2 + maven. Il test di JUnit non ha trovato le mie entità ma con questa impostazione ha funzionato.
Sabato

8

È possibile fornire il jar-filepercorso dell'elemento a una cartella con classi compilate. Ad esempio ho aggiunto qualcosa del genere quando ho preparato persistence.xml ad alcuni test di integrazione:

 <jar-file>file:../target/classes</jar-file>

Questo è quello che stavo cercando!
xtian

Funziona anche con EclipseLink!
Bombe

8

per JPA 2+ questo fa il trucco

 <jar-file></jar-file>

scansiona tutti i barattoli in guerra per le classi @Entity annotate


2
hai maggiori informazioni in merito? funziona per caso o è scritto nelle specifiche? Dipende dall'implementazione?
markus

lo scanner è in classe che estende AbstractScannerImpl, ibernazione - non ho idea se si tratta di bug o funzionalità, mi dispiace
eriskooo

1
In Java SE con Hibernate 5.1.2.Final, questa soluzione non funziona. Hibernate si aspetta un nome di file jar ( java.lang.IllegalArgumentException: Unable to visit JAR file:).
Stephan

1
lavori! :) con WildFly 8.2.1.Final + Hibernate 4.3.7.Final
Andreas Dietrich

Grazie amico, ho cercato molto e questa è la soluzione più ordinata disponibile. Wildfly10 + Hibernate 5.0.7 funzionante.
circa il

7

Hibernate non supporta <exclude-unlisted-classes>false</exclude-unlisted-classes>in SE, (un altro poster ha menzionato che funziona con TopLink ed EclipseLink).

Sono disponibili strumenti che generano automaticamente l'elenco delle classi in persistence.xml, ad esempio la procedura guidata Importa schema database in IntelliJ. Una volta ottenute le classi iniziali del progetto in persistence.xml, dovrebbe essere semplice aggiungere / rimuovere singole classi manualmente man mano che il progetto procede.


Il rilevamento automatico delle entità in Java SE non fa parte di JPA. Le applicazioni che si basano su questo non sono portabili.
Pascal Thivent

4

Non sono sicuro se stai facendo qualcosa di simile a quello che sto facendo, ma sto generando un carico di java sorgente da un XSD usando JAXB in un componente separato usando Maven. Diciamo che questo artefatto si chiama "modello base"

Volevo importare questo artefatto contenente l'origine java ed eseguire l'ibernazione su tutte le classi nel mio vaso di artefatto "modello base" e non specificarlo esplicitamente. Sto aggiungendo "base-model" come dipendenza per il mio componente di ibernazione, ma il problema è che il tag in persistence.xml ti consente solo di specificare percorsi assoluti.

Il modo in cui ho aggirato la cosa è copiare la mia dipendenza da jar "base-model" esplicitamente nella mia directory di destinazione e rimuovere anche la versione di esso. Quindi, mentre se costruisco il mio artefatto "base-model" esso genera "base-model-1.0-SNAPSHOT.jar", il passaggio copy-resources lo copia come "base-model.jar".

Quindi nel tuo pom per il componente di ibernazione:

            <!-- 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>

Quindi chiamo il plug-in di ibernazione nella fase successiva "classi di processo":

            <!-- 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>

e infine nel mio persistence.xml posso impostare esplicitamente la posizione del jar così:

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

e aggiungi la proprietà:

<property name="hibernate.archive.autodetection" value="class, hbm"/>

3

Non è una soluzione ma un suggerimento per chi usa Spring:

Ho provato ad utilizzare org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeancon setting persistenceXmlLocationma con questo ho dovuto fornire gli <class>elementi (anche se persistenceXmlLocationsolo puntati META-INF/persistence.xml).

Quando non lo uso persistenceXmlLocationpotrei omettere questi <class>elementi.


Ho usato persistenceXmlLocationproprietà nelle mie LocalContainerEntityManagerFactoryBeanimpostazioni. Ma tutte le query funzionano anche se ometto gli <class>elementi. È su un'applicazione Spring / Hibernate / Maven. Ma nel tuo suggerimento dici che "Quando non uso persistenceXmlLocation potrei omettere questi elementi <class>." ma per me è il contrario.
Lucky

@Ethan hai ragione, perché persistenceXmlLocation ha la priorità su packagesToScan, se guardi nei sorgenti. Quindi non usarlo, quando usi packagesToScan.
Artem Novikov

2

Non sono sicuro che questa soluzione sia conforme alle specifiche, ma penso di poter condividere per altri.

albero delle dipendenze

my-entities.jar

Contiene solo classi di entità. No META-INF/persistence.xml.

my-services.jar

Dipende da my-entities. Contiene solo EJB.

my-resources.jar

Dipende da my-services. Contiene classi di risorse e META-INF/persistence.xml.

i problemi

  • Come possiamo specificare <jar-file/>elemento in my-resourcescome il nome artefatto postfissato dalla versione di una dipendenza temporanea?
  • Come possiamo sincronizzare il <jar-file/>valore dell'elemento e quello della dipendenza transitoria effettiva?

soluzione

dipendenza diretta (ridondante?) e filtro delle risorse

Ho messo una proprietà e una dipendenza 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>

Ora persistence.xmlpreparati per essere filtrato

<?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>

Plugin Maven Enforcer

Con la dependencyConvergenceregola possiamo assicurare che l my-entities'versione è la stessa sia in diretta che in 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>

0

Non necessariamente in tutti i casi.

Sto usando Jboss 7.0.8 ed Eclipselink 2.7.0. Nel mio caso per caricare entità senza aggiungere lo stesso in persistence.xml, ho aggiunto la seguente proprietà di sistema in Jboss Standalone XML:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.