Ai-je besoin d'éléments <class> dans persistence.xml?

110

J'ai un fichier persistance.xml très 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>

et il fonctionne.

Mais lorsque je supprime des <class>éléments, l'application ne voit pas les entités (toutes les classes sont annotées avec @Entity).

Existe-t-il un mécanisme automatique pour rechercher des @Entityclasses?

Michał Mech
la source

Réponses:

78

Le persistence.xml a un jar-fileque vous pouvez utiliser. À partir du didacticiel 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>

Ce fichier définit une unité de persistance nommée OrderManagement, qui utilise une source de données compatible JTA jdbc/MyOrderDB. Les éléments jar-fileet classspécifient des classes de persistance gérées: classes d'entité, classes intégrables et superclasses mappées. L' jar-fileélément spécifie les fichiers JAR visibles par l'unité de persistance empaquetée qui contiennent des classes de persistance gérées, tandis que l' classélément nomme explicitement les classes de persistance gérées.

Dans le cas d'Hibernate, jetez un œil au Chapter2. Installation et configuration aussi pour plus de détails.

EDIT: En fait, si cela ne vous dérange pas de ne pas être conforme aux spécifications, Hibernate prend en charge la détection automatique même dans Java SE. Pour ce faire, ajoutez la hibernate.archive.autodetectionpropriété:

<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
la source
13
Je vois, mais les entités (@Entity) sont dans un projet Maven séparé, donc le nom du fichier jar peut changer à chaque construction. Je cherche quelque chose pour tout analyser dans un package ou un chemin de classe spécifique. Je suis juste trop paresseux pour taper de très nombreux éléments <class> dans le fichier persistence.xml.
Michał Mech
Sur chaque build?! Je ne vous demanderai même pas pourquoi mais ... vous pouvez utiliser le filtrage pour résoudre ce problème.
Pascal Thivent
Pas tout le monde exactement mais je veux résister aux changements.
Michał Mech
5
Ancien fil, je sais, mais jetez un œil au plugin jpa-maven .
Laird Nelson
Vous pouvez utiliser l'élément <mapping-file> (qui contient la liste des entités) dans persistence.xml, afin de pouvoir conserver le même nom des fichiers utilisés et les intégrer dans la construction des jars référencés.
med_alpa
44

Dans l'environnement Java SE, par spécification, vous devez spécifier toutes les classes comme vous l'avez fait:

Une liste de toutes les classes de persistance gérées nommées doit être spécifiée dans les environnements Java SE pour assurer la portabilité

et

S'il n'est pas prévu que les classes de persistance annotées contenues dans la racine de l'unité de persistance soient incluses dans l'unité de persistance, l'élément exclude-unlisted-classes doit être utilisé. L'élément exclude-unlisted-classes n'est pas destiné à être utilisé dans les environnements Java SE.

(JSR-000220 6.2.1.6)

Dans les environnements Java EE, vous n'êtes pas obligé de le faire car le fournisseur recherche les annotations pour vous.

Officieusement, vous pouvez essayer de définir <exclude-unlisted-classes>false</exclude-unlisted-classes>dans votre persistence.xml. Ce paramètre est défini par défaut sur falseEE et trueSE. Les deux EclipseLink et Toplink soutient jusqu'à ce que je peux dire. Mais vous ne devez pas compter sur son fonctionnement en SE, selon les spécifications, comme indiqué ci-dessus.

Vous pouvez ESSAYER ce qui suit (peut ou non fonctionner dans les environnements 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
la source
2
<exclude-unlisted-classes>false</exclude-unlisted-classes>n'a pas fonctionné avec WildFly 8.2.1.Final + Hibernate 4.3.7
Andreas Dietrich
12

Ai-je besoin d'éléments de classe dans persistence.xml?

Non, pas nécessairement. Voici comment procéder dans Eclipse (testé par Kepler):

Faites un clic droit sur le projet, cliquez sur Propriétés , sélectionnez JPA , dans la gestion des classes de persistance, cochez Découvrir automatiquement les classes annotées .

entrez la description de l'image ici

Abbas
la source
9
Pourquoi voter? OP ne mentionne même pas Eclipse et cette réponse ne montre pas ce que cette fonctionnalité Eclipse fait sous le capot pour que l'on puisse le faire sans IDE.
Artem Novikov
2
@Artem Novikov: Je trouve cela trop dur car souvent la question se pose dans différents environnements et ici nous voulons aider ou donner des indices utiles! (comme pour moi) C'est utile car Eclipse est un IDE commun pour développer comme ça et sous le capot n'est pas si important, mais je suppose qu'il inclura tous les projets d'espace de travail pertinents (par exemple, mon projet dépend de).
Andreas Dietrich
stackoverflow.com/questions/17951297/ ... belle astuce, mais apparemment cela ne fonctionne que si les entités se retrouvent dans le même classloader que persistence.xml
Pierluigi Vernetto
@abbas Veuillez montrer persistence.xmlce qu'Eclipse génère.
Frans
12

Pour ceux qui exécutent JPA au printemps, à partir de la version 3.1, vous pouvez définir la packagesToScanpropriété sous LocalContainerEntityManagerFactoryBeanet vous débarrasser complètement de persistence.xml.

Voici le bas

Christopher Yang
la source
A travaillé pour moi! Le scénario était le printemps 4 + hibernation + jpa2 + maven. Les tests JUnit n'ont pas trouvé mes entités mais avec ce paramètre, ils ont fait le travail.
SatA
8

Vous pouvez fournir le jar-filechemin de l'élément vers un dossier avec des classes compilées. Par exemple, j'ai ajouté quelque chose comme ça lorsque j'ai préparé persistence.xml à certains tests d'intégration:

 <jar-file>file:../target/classes</jar-file>
Arek Trzepacz
la source
C'est ce que je cherchais!
xtian
Fonctionne également avec EclipseLink!
Bombe
8

pour JPA 2+ cela fait l'affaire

 <jar-file></jar-file>

scannez tous les bocaux en guerre pour les classes @Entity annotées

Eriskooo
la source
2
avez-vous plus d'informations à ce sujet? cela fonctionne-t-il par accident ou est-il écrit dans la spécification? Cela dépend-il de la mise en œuvre?
markus
scanner est dans la classe étendant AbstractScannerImpl, hibernate - aucune idée si c'est un bogue ou une fonctionnalité, désolé
eriskooo
1
Dans Java SE avec Hibernate 5.1.2.Final, cette solution ne fonctionne pas. Hibernate attend un nom de fichier jar ( java.lang.IllegalArgumentException: Unable to visit JAR file:).
Stephan
1
travaux! :) avec WildFly 8.2.1.Final + Hibernate 4.3.7.Final
Andreas Dietrich
Thx man, j'ai beaucoup cherché et c'est la solution la plus soignée disponible. Wildfly10 + Hibernate 5.0.7 fonctionne.
boutta
7

Hibernate ne prend pas en charge <exclude-unlisted-classes>false</exclude-unlisted-classes>sous SE (un autre poster a mentionné que cela fonctionne avec TopLink et EclipseLink).

Il existe des outils qui génèrent automatiquement la liste des classes vers persistence.xml, par exemple l'assistant d'importation de schéma de base de données dans IntelliJ. Une fois que vous avez les classes initiales de votre projet dans persistence.xml, il devrait être simple d'ajouter / supprimer des classes individuelles à la main au fur et à mesure que votre projet progresse.

Chuck Stephanski
la source
La détection automatique des entités dans Java SE ne fait tout simplement pas partie de JPA. Les applications qui en dépendent ne sont pas portables.
Pascal Thivent
4

Je ne sais pas si vous faites quelque chose de similaire à ce que je fais, mais je génère une charge de source java à partir d'un XSD en utilisant JAXB dans un composant séparé en utilisant Maven. Disons que cet artefact est appelé "modèle de base"

Je voulais importer cet artefact contenant la source java et exécuter hibernate sur toutes les classes de mon jar d'artefact "modèle de base" et ne pas les spécifier explicitement. J'ajoute "base-model" comme dépendance pour mon composant hibernate mais le problème est que la balise dans persistence.xml vous permet seulement de spécifier des chemins absolus.

La façon dont je l'ai contourné est de copier explicitement ma dépendance jar "modèle de base" dans mon répertoire cible et de supprimer la version de celui-ci. Ainsi, alors que si je construis mon artefact "base-model", il génère "base-model-1.0-SNAPSHOT.jar", l'étape de copie-ressources le copie comme "base-model.jar".

Donc, dans votre pom pour le composant hibernate:

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

Ensuite, j'appelle le plugin hibernate dans la phase suivante "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>

et enfin dans mon persistence.xml, je peux définir explicitement l'emplacement du jar ainsi:

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

et ajoutez la propriété:

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

Ce n'est pas une solution mais un indice pour ceux qui utilisent Spring:

J'ai essayé de l'utiliser org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeanavec le réglage persistenceXmlLocationmais avec cela, je devais fournir les <class>éléments (même si ceux-ci persistenceXmlLocationvenaient de pointer META-INF/persistence.xml).

Lorsque je n'utilise pas,persistenceXmlLocation je pourrais omettre ces <class>éléments.

Ethan Leroy
la source
J'ai utilisé la persistenceXmlLocationpropriété dans mes LocalContainerEntityManagerFactoryBeanparamètres. Mais toutes les requêtes fonctionnent même si j'omets les <class>éléments. C'est sur une application Spring / Hibernate / Maven. Mais dans votre allusion, vous dites que "lorsque je n'utilise pas persistenceXmlLocation, je pourrais omettre ces éléments <class>." mais c'est l'inverse pour moi.
Lucky
@Et que vous avez raison, car persistenceXmlLocation remplace packagesToScan - si vous regardez dans les sources. Ne l'utilisez donc pas lorsque vous utilisez packagesToScan.
Artem Novikov
2

Je ne suis pas sûr que cette solution soit conforme aux spécifications, mais je pense que je peux partager pour d'autres.

arbre de dépendance

mes-entités.jar

Contient uniquement des classes d'entités. Non META-INF/persistence.xml.

mes-services.jar

Cela dépend my-entities. Contient uniquement des EJB.

my-resources.jar

Cela dépend my-services. Contient des classes de ressources et META-INF/persistence.xml.

problèmes

  • Comment pouvons-nous spécifier <jar-file/>element in my-resourcescomme nom d'artefact postfixé de version d'une dépendance transitoire?
  • Comment pouvons-nous synchroniser la <jar-file/>valeur de l' élément et celle de la dépendance transitoire réelle?

Solution

Dépendance directe (redondante?) et filtrage des ressources

J'ai mis une propriété et une dépendance 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>

Maintenant, préparez- persistence.xmlvous à être filtré

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

Avec la dependencyConvergencerègle, nous pouvons garantir que la my-entities«version est la même en direct et transitif.

<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
la source
0

Pas nécessairement dans tous les cas.

J'utilise Jboss 7.0.8 et Eclipselink 2.7.0. Dans mon cas, pour charger des entités sans ajouter la même chose dans persistence.xml, j'ai ajouté la propriété système suivante dans Jboss Standalone XML:

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

Gandhi
la source