Benötige ich <class> -Elemente in persistence.xml?

110

Ich habe eine sehr einfache persistance.xml-Datei:

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

und es funktioniert.

Wenn ich jedoch <class>Elemente entferne, werden in der Anwendung keine Entitäten angezeigt (alle Klassen sind mit Anmerkungen versehen@Entity ).

Gibt es einen automatischen Mechanismus zum Suchen nach @EntityKlassen?

Michał Mech
quelle

Antworten:

78

Die persistence.xml hat eine jar-file, die Sie verwenden können. Aus dem Java EE 5-Tutorial :

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

Diese Datei definiert eine Persistenzeinheit mit dem Namen OrderManagement, die eine JTA-fähige Datenquelle verwendet jdbc/MyOrderDB. Die Elemente jar-fileund classgeben verwaltete Persistenzklassen an: Entitätsklassen, einbettbare Klassen und zugeordnete Superklassen. Das jar-fileElement gibt JAR-Dateien an, die für die gepackte Persistenzeinheit sichtbar sind und verwaltete Persistenzklassen enthalten, während das classElement verwaltete Persistenzklassen explizit benennt.

Schauen Sie sich im Fall von Hibernate das Kapitel 2 an. Setup und Konfiguration für weitere Details.

BEARBEITEN: Wenn es Ihnen nichts ausmacht, nicht spezifikationskonform zu sein, unterstützt Hibernate die automatische Erkennung auch in Java SE. Fügen Sie dazu die hibernate.archive.autodetectionEigenschaft hinzu:

<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
quelle
13
Ich verstehe, aber die Entitäten (@Entity) befinden sich in einem separaten Maven-Projekt, sodass sich der Name der JAR-Datei bei jedem Build ändern kann. Ich suche etwas, um alles in einem bestimmten Paket oder Klassenpfad zu scannen. Ich bin einfach zu faul, um viele, viele <class> -Elemente in die Datei persistence.xml einzugeben.
Michał Mech
Bei jedem Build?! Ich werde nicht einmal fragen warum, aber ... Sie könnten Filter verwenden, um dies zu lösen.
Pascal Thivent
Nicht jeder genau, aber ich möchte gegen Veränderungen resistent sein.
Michał Mech
5
Alter Thread, ich weiß, aber schauen Sie sich das jpa-maven-Plugin an .
Laird Nelson
Sie können das Element <mapping-file> (das die Liste der Entitäten enthält) in persistence.xml verwenden, sodass Sie den gleichen Namen der verwendeten Dateien beibehalten und diese in den Build der referenzierten Jars integrieren können.
med_alpa
44

In der Java SE-Umgebung müssen Sie alle Klassen wie angegeben angeben :

In Java SE-Umgebungen muss eine Liste aller benannten verwalteten Persistenzklassen angegeben werden, um die Portabilität sicherzustellen

und

Wenn nicht beabsichtigt ist, dass die im Stammverzeichnis der Persistenzeinheit enthaltenen annotierten Persistenzklassen in der Persistenzeinheit enthalten sind, sollte das Element exclude-unlisted-classes verwendet werden. Das Element exclude-unlisted-classes ist nicht für die Verwendung in Java SE-Umgebungen vorgesehen.

(JSR-000220 6.2.1.6)

In Java EE-Umgebungen ist dies nicht der Fall tun, da der Anbieter nach Anmerkungen für Sie sucht.

Inoffiziell können Sie versuchen, <exclude-unlisted-classes>false</exclude-unlisted-classes>in Ihrer persistence.xml festzulegen. Dieser Parameter ist standardmäßig falsein EE und truein SE. Sowohl EclipseLink als auch Toplink unterstützen dies, soweit ich das kann. Sie sollten sich jedoch nicht darauf verlassen, dass es gemäß den oben angegebenen Spezifikationen in SE funktioniert.

Sie können Folgendes VERSUCHEN (kann in SE-Umgebungen funktionieren oder nicht):

<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
quelle
2
<exclude-unlisted-classes>false</exclude-unlisted-classes>funktionierte nicht mit WildFly 8.2.1.Final + Hibernate 4.3.7
Andreas Dietrich
12

Benötige ich Klassenelemente in persistence.xml?

Nein, das musst du nicht. So geht's in Eclipse (Kepler getestet):

Klicken Sie mit der rechten Maustaste auf das Projekt, klicken Sie auf Eigenschaften , wählen Sie JPA aus , und aktivieren Sie im Kontrollkästchen Persistenzklassenverwaltung die Option Kommentierte Klassen automatisch erkennen .

Geben Sie hier die Bildbeschreibung ein

abbas
quelle
9
Warum upvote? OP erwähnt Eclipse nicht einmal und diese Antwort zeigt nicht, was diese Eclipse-Funktion unter der Haube tut, so dass man dies ohne eine IDE tun kann.
Artem Novikov
2
@Artem Novikov: Ich finde das zu hart, da die Frage oft aus verschiedenen Umgebungen kommt und wir hier helfen oder nützliche Hinweise geben wollen! (wie für mich) Es ist nützlich, da Eclipse eine gängige IDE für die Entwicklung auf diese Weise ist und unter der Haube nicht so wichtig ist, aber ich denke, es wird alle relevanten Arbeitsbereichsprojekte enthalten (z. B. hängt mein Projekt davon ab).
Andreas Dietrich
stackoverflow.com/questions/17951297/… netter Trick, aber anscheinend funktioniert er nur, wenn Entitäten im selben Klassenladeprogramm wie persistence.xml
landen
@abbas Bitte zeigen Sie, persistence.xmlwas Eclipse generiert.
Frans
12

Für diejenigen, die JPA im Frühjahr ausführen, können Sie ab Version 3.1 die packagesToScanEigenschaft unter festlegen LocalContainerEntityManagerFactoryBeanund persistence.xml insgesamt entfernen.

Hier ist die Übersicht

Christopher Yang
quelle
Hat für mich gearbeitet! Das Szenario war Frühling 4 + Ruhezustand + jpa2 + Maven. JUnit-Tests haben meine Entitäten nicht gefunden, aber mit dieser Einstellung hat es den Job gemacht.
SatA
8

Sie können einen jar-fileElementpfad zu einem Ordner mit kompilierten Klassen angeben. Zum Beispiel habe ich so etwas hinzugefügt, als ich persistence.xml für einige Integrationstests vorbereitet habe:

 <jar-file>file:../target/classes</jar-file>
Arek Trzepacz
quelle
Das habe ich gesucht!
Xtian
Funktioniert auch mit EclipseLink!
Bombe
8

Für JPA 2+ ist dies der Trick

 <jar-file></jar-file>

Scannen Sie alle Gläser im Krieg nach kommentierten @ Entity-Klassen

eriskooo
quelle
2
Haben Sie weitere Informationen dazu? Funktioniert dies versehentlich oder ist es in der Spezifikation geschrieben? Ist es abhängig von der Implementierung?
Markus
Scanner ist in der Klasse, die AbstractScannerImpl erweitert, Ruhezustand - keine Ahnung, ob es sich um einen Fehler oder eine Funktion handelt, sorry
eriskooo
1
In Java SE mit Hibernate 5.1.2.Final funktioniert diese Lösung nicht. Hibernate erwartet einen JAR-Dateinamen ( java.lang.IllegalArgumentException: Unable to visit JAR file:).
Stephan
1
funktioniert! :) mit WildFly 8.2.1.Final + Hibernate 4.3.7.Final
Andreas Dietrich
Vielen Dank, viel gesucht und dies ist die sauberste verfügbare Lösung. Wildfly10 + Hibernate 5.0.7 funktioniert.
Boutta
7

Der Ruhezustand wird <exclude-unlisted-classes>false</exclude-unlisted-classes>unter SE nicht unterstützt (ein anderes Poster erwähnte, dass dies mit TopLink und EclipseLink funktioniert).

Es gibt Tools, die die Liste der Klassen in persistence.xml automatisch generieren, z. B. den Assistenten zum Importieren von Datenbankschemas in IntelliJ. Sobald Sie die ersten Klassen Ihres Projekts in persistence.xml haben, sollte es einfach sein, einzelne Klassen im Verlauf Ihres Projekts von Hand hinzuzufügen / zu entfernen.

Chuck Stephanski
quelle
Die automatische Erkennung von Entitäten in Java SE ist einfach nicht Teil von JPA. Anwendungen, die sich darauf verlassen, sind nicht portierbar.
Pascal Thivent
4

Ich bin mir nicht sicher, ob Sie etwas Ähnliches tun wie ich, aber ich generiere eine Ladung Quell-Java von einer XSD mit JAXB in einer separaten Komponente mit Maven. Nehmen wir an, dieses Artefakt heißt "Basismodell".

Ich wollte dieses Artefakt, das die Java-Quelle enthält, importieren und den Ruhezustand über alle Klassen in meinem Artefakt-Jar "Basismodell" ausführen und nicht jedes explizit angeben. Ich füge "Basismodell" als Abhängigkeit für meine Ruhezustandskomponente hinzu, aber das Problem ist, dass das Tag in persistence.xml nur die Angabe absoluter Pfade ermöglicht.

Die Art und Weise, wie ich es umgangen habe, besteht darin, meine "Basismodell" -Jar-Abhängigkeit explizit in mein Zielverzeichnis zu kopieren und auch die Version davon zu entfernen. Wenn ich also mein Artefakt "Basismodell" erstelle, wird "Basismodell 1.0-SNAPSHOT.jar" generiert, und der Schritt "Kopierressourcen" kopiert es als "Basismodell.jar".

Also in deinem Pom für die Hibernate-Komponente:

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

Dann nenne ich das Hibernate-Plugin in der nächsten Phase "Prozessklassen":

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

und schließlich kann ich in meiner persistence.xml die Position des Glases explizit so einstellen:

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

und fügen Sie die Eigenschaft hinzu:

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

Es ist keine Lösung, sondern ein Hinweis für diejenigen, die Spring verwenden:

Ich habe versucht, org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeanmit Einstellung zu verwenden , persistenceXmlLocationaber damit musste ich die <class>Elemente bereitstellen (auch wenn die persistenceXmlLocationgerade darauf hinwiesenMETA-INF/persistence.xml ).

Wenn ich es nicht benutze, persistenceXmlLocationkönnte ich diese <class>Elemente weglassen .

Ethan Leroy
quelle
Ich habe persistenceXmlLocationEigenschaft in meinen LocalContainerEntityManagerFactoryBeanEinstellungen verwendet. Aber alle Abfragen funktionieren, auch wenn ich die <class>Elemente weglasse . Es ist auf einer Spring / Hibernate / Maven-Anwendung. In Ihrem Hinweis heißt es jedoch: "Wenn Sie persistenceXmlLocation nicht verwenden, kann ich diese <class> -Elemente weglassen." aber es ist umgekehrt für mich.
Glücklicher
@Ethan Sie haben Recht, weil persistenceXmlLocation packagesToScan überschreibt - wenn Sie in den Quellen suchen. Verwenden Sie es also nicht, wenn Sie packagesToScan verwenden.
Artem Novikov
2

Ich bin nicht sicher, ob diese Lösung unter der Spezifikation liegt, aber ich denke, ich kann sie für andere teilen.

Abhängigkeitsbaum

my-entity.jar

Enthält nur Entitätsklassen. Nein META-INF/persistence.xml.

my-services.jar

Kommt drauf an my-entities . Enthält nur EJBs.

my-resources.jar

Kommt drauf an my-services. Enthält Ressourcenklassen undMETA-INF/persistence.xml .

Probleme

  • Wie können wir ein <jar-file/>Element in angeben ?my-resources als den nachträglich fixierten Artefaktnamen einer vorübergehenden Abhängigkeit ?
  • Wie können wir den <jar-file/>Wert des Elements und den Wert der tatsächlichen vorübergehenden Abhängigkeit synchronisieren ?

Lösung

direkte (redundante?) Abhängigkeit und Ressourcenfilterung

Ich habe eine Eigenschaft und eine Abhängigkeit in 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>

Bereiten Sie sich jetzt darauf vor persistence.xml, gefiltert zu werden

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

Maven Enforcer Plugin

Mit der dependencyConvergenceRegel können wir sicherstellen, dass die my-entitiesVersion sowohl direkt als auch transitiv gleich ist.

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

Nicht unbedingt in allen Fällen.

Ich verwende Jboss 7.0.8 und Eclipselink 2.7.0. In meinem Fall, um Entitäten zu laden, ohne sie in persistence.xml hinzuzufügen, habe ich die folgende Systemeigenschaft in Jboss Standalone XML hinzugefügt:

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

Gandhi
quelle