Apakah saya memerlukan elemen <class> di persistence.xml?

110

Saya memiliki file persistance.xml yang sangat sederhana:

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

dan berhasil.

Tetapi ketika saya menghapus <class>elemen aplikasi tidak melihat entitas (semua kelas dianotasi dengan @Entity).

Apakah ada mekanisme otomatis untuk memindai @Entitykelas?

Michał Mech
sumber

Jawaban:

78

Persistence.xml memiliki jar-fileyang dapat Anda gunakan. Dari 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>

File ini mendefinisikan unit persistensi bernama OrderManagement, yang menggunakan sumber data yang sadar-JTA jdbc/MyOrderDB. The jar-filedan classelemen sebutkan dikelola kelas ketekunan: kelas entitas, kelas embeddable, dan superclasses dipetakan. The jar-fileelemen menspesifikasikan file JAR yang terlihat pada unit kegigihan kemasan yang berisi dikelola ketekunan kelas, sedangkan classunsur eksplisit nama dikelola ketekunan kelas.

Dalam kasus Hibernate, lihat Bab2. Setup dan konfigurasi juga untuk lebih jelasnya.

EDIT: Sebenarnya, Jika Anda tidak keberatan tidak sesuai spesifikasi, Hibernate mendukung deteksi otomatis bahkan di Java SE. Untuk melakukannya, tambahkan hibernate.archive.autodetectionproperti:

<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
sumber
13
Begitu, tetapi entitas (@Entity) berada dalam proyek Maven yang terpisah, jadi nama file jar dapat berubah di setiap build. Saya mencari sesuatu untuk dipindai semua dalam paket atau jalur kelas tertentu. Saya hanya malas mengetik banyak, banyak elemen <class> di file persistence.xml.
Michał Mech
Di setiap bangunan ?! Saya bahkan tidak akan bertanya mengapa tetapi ... Anda dapat menggunakan penyaringan untuk menyelesaikan ini.
Pascal Thivent
Tidak semua orang persis tapi saya ingin tahan terhadap perubahan.
Michał Mech
5
Utas kuno, saya tahu, tapi lihatlah jpa-maven-plugin .
Laird Nelson
Anda bisa menggunakan elemen <mapping-file> (yang berisi daftar entitas) di persistence.xml, sehingga Anda bisa menyimpan nama yang sama dari file yang digunakan dan mengintegrasikannya dalam build toples yang direferensikan.
med_alpa
44

Di lingkungan Java SE, dengan spesifikasi Anda harus menentukan semua kelas seperti yang telah Anda lakukan:

Daftar semua kelas persistensi terkelola yang bernama harus ditentukan di lingkungan Java SE untuk memastikan portabilitas

dan

Jika kelas persistensi beranotasi yang terdapat di root unit persistensi tidak dimaksudkan untuk disertakan dalam unit persistensi, elemen exclude-unlisted-class harus digunakan. Elemen exclude-unlisted-class tidak dimaksudkan untuk digunakan di lingkungan Java SE.

(JSR-000220 6.2.1.6)

Di lingkungan Java EE, Anda tidak perlu melakukan ini karena penyedia memindai anotasi untuk Anda.

Secara tidak resmi, Anda dapat mencoba menyetel <exclude-unlisted-classes>false</exclude-unlisted-classes>di persistence.xml Anda. Parameter ini secara default falsedi EE dan trueSE. Baik EclipseLink dan Toplink mendukung ini sejauh yang saya tahu. Tetapi Anda tidak harus mengandalkannya bekerja di SE, menurut spesifikasi, seperti yang dinyatakan di atas.

Anda dapat MENCOBA berikut ini (mungkin atau mungkin tidak bekerja di lingkungan 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
sumber
2
<exclude-unlisted-classes>false</exclude-unlisted-classes>tidak bekerja dengan WildFly 8.2.1. Final + Hibernate 4.3.7
Andreas Dietrich
12

Apakah saya memerlukan elemen Kelas di persistence.xml?

Tidak, Anda belum tentu. Inilah cara Anda melakukannya di Eclipse (diuji Kepler):

Klik kanan pada proyek, klik Properties , pilih JPA , di manajemen kelas Persistence centang Temukan kelas beranotasi secara otomatis .

masukkan deskripsi gambar di sini

abbas
sumber
9
Mengapa upvote? OP bahkan tidak menyebutkan Eclipse dan jawaban ini tidak menunjukkan apa yang dilakukan fitur Eclipse ini di bawah tenda sehingga seseorang dapat melakukannya tanpa IDE.
Artem Novikov
2
@Artem Novikov: Menurut saya ini kasar karena sering kali pertanyaan muncul dari lingkungan yang berbeda dan di sini kami ingin membantu atau memberikan petunjuk yang berguna! (seperti untuk saya) Ini berguna karena Eclipse adalah IDE umum untuk pengembangan seperti ini dan di bawah tenda tidak begitu penting, tapi saya rasa ini akan mencakup semua proyek ruang kerja yang relevan (misalnya proyek saya bergantung pada).
Andreas Dietrich
stackoverflow.com/questions/17951297/… trik yang bagus, tetapi tampaknya ini hanya berfungsi jika entitas berakhir di classloader yang sama dengan persistence.xml
Pierluigi Vernetto
@abbas Harap tunjukkan persistence.xmlyang dihasilkan Eclipse.
Frans
12

Untuk mereka yang menjalankan JPA di Spring, dari versi 3.1 dan seterusnya, Anda dapat menyetel packagesToScanproperti di bawah LocalContainerEntityManagerFactoryBeandan menghapus persistence.xml sekaligus.

Inilah bagian bawahnya

Christopher Yang
sumber
Bekerja untuk saya! Skenario ini adalah musim semi 4 + hibernate + jpa2 + maven. Pengujian JUnit tidak menemukan entitas saya tetapi dengan pengaturan ini berhasil.
SatA
8

Anda dapat menyediakan jar-filejalur elemen ke folder dengan kelas yang dikompilasi. Misalnya saya menambahkan sesuatu seperti itu ketika saya menyiapkan persistence.xml ke beberapa tes integrasi:

 <jar-file>file:../target/classes</jar-file>
Arek Trzepacz
sumber
Inilah yang saya cari!
xtian
Bekerja dengan EclipseLink juga!
Bombe
8

untuk JPA 2+ ini berhasil

 <jar-file></jar-file>

pindai semua toples dalam perang untuk mencari kelas @Entity beranotasi

eriskooo
sumber
2
apakah Anda memiliki informasi lebih lanjut tentang ini? apakah ini bekerja secara tidak sengaja atau apakah itu tertulis dalam spesifikasi? Apakah tergantung pada implementasinya?
markus
pemindai di kelas memperluas AbstractScannerImpl, hibernasi - tidak tahu apakah itu bug atau fitur, maaf
eriskooo
1
Di Java SE dengan Hibernate 5.1.2. Terakhir, solusi ini tidak berfungsi. Hibernate mengharapkan nama file jar ( java.lang.IllegalArgumentException: Unable to visit JAR file:).
Stephan
1
berhasil! :) dengan WildFly 8.2.1. Final + Hibernate 4.3.7. Final
Andreas Dietrich
Terima kasih, banyak mencari dan ini adalah solusi paling rapi yang tersedia. Wildfly10 + Hibernate 5.0.7 bekerja.
Tentang
7

Hibernate tidak mendukung di <exclude-unlisted-classes>false</exclude-unlisted-classes>bawah SE, (poster lain menyebutkan ini berfungsi dengan TopLink dan EclipseLink).

Ada alat yang akan menghasilkan daftar kelas secara otomatis ke persistence.xml misalnya wizard Import Database Schema di IntelliJ. Setelah Anda mendapatkan kelas awal proyek Anda di persistence.xml, semestinya mudah untuk menambahkan / menghapus satu kelas secara manual saat proyek Anda berjalan.

Chuck Stephanski
sumber
Deteksi otomatis entitas di Java SE bukan bagian dari JPA. Aplikasi yang mengandalkan ini tidak portabel.
Pascal Thivent
4

Tidak yakin apakah Anda melakukan sesuatu yang mirip dengan apa yang saya lakukan, tetapi Im menghasilkan beban java sumber dari XSD menggunakan JAXB dalam komponen terpisah menggunakan Maven. Katakanlah artefak ini disebut "model-dasar"

Saya ingin mengimpor artefak ini yang berisi sumber java dan menjalankan hibernasi di semua kelas di toples artefak "model dasar" saya dan tidak menentukan masing-masing secara eksplisit. Saya menambahkan "model-dasar" sebagai ketergantungan untuk komponen hibernasi saya, tetapi masalahnya adalah tag di persistence.xml hanya memungkinkan Anda untuk menentukan jalur absolut.

Cara saya mengatasinya adalah dengan menyalin ketergantungan jar "model dasar" saya secara eksplisit ke direktori target saya dan juga menghapus versinya. Jadi jika saya membangun artefak "model-dasar", ia menghasilkan "model-dasar-1.0-SNAPSHOT.jar", langkah sumber-salinan menyalinnya sebagai "basis-model.jar".

Jadi di pom Anda untuk komponen hibernasi:

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

Kemudian saya memanggil plugin hibernate di tahap berikutnya "kelas proses":

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

dan akhirnya di persistence.xml saya, saya dapat secara eksplisit mengatur lokasi jar sebagai:

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

dan tambahkan properti:

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

Ini bukan solusi tapi petunjuk bagi mereka yang menggunakan Spring:

Saya mencoba menggunakan org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeandengan pengaturan persistenceXmlLocationtetapi dengan ini saya harus menyediakan <class>elemen (bahkan jika persistenceXmlLocationhanya menunjuk META-INF/persistence.xml).

Saat tidak menggunakan, persistenceXmlLocationsaya bisa menghilangkan <class>elemen ini .

Ethan Leroy
sumber
Saya menggunakan persistenceXmlLocationproperti dalam LocalContainerEntityManagerFactoryBeanpengaturan saya . Tetapi semua kueri berfungsi bahkan jika saya menghilangkan <class>elemen. Ini pada aplikasi Spring / Hibernate / Maven. Tapi dalam petunjuk Anda, Anda mengatakan bahwa "Saat tidak menggunakan persistenceXmlLocation saya bisa menghilangkan elemen <class> ini." tapi itu sebaliknya bagiku.
Beruntung
@Ethan Anda benar, karena persistenceXmlLocation menimpa packagesToScan - jika Anda melihat di sumbernya. Jadi jangan gunakan itu, saat menggunakan packagesToScan.
Artem Novikov
2

Saya tidak yakin solusi ini sesuai dengan spesifikasi tetapi saya rasa saya dapat membagikan untuk orang lain.

pohon ketergantungan

my-entity.jar

Berisi kelas entitas saja. Tidak META-INF/persistence.xml.

my-services.jar

Tergantung my-entities. Berisi EJB saja.

my-resources.jar

Tergantung my-services. Berisi kelas sumber daya dan META-INF/persistence.xml.

masalah

  • Bagaimana kita dapat menetapkan <jar-file/>elemen my-resourcessebagai nama artefak versi-postfixed dari ketergantungan sementara?
  • Bagaimana kita bisa menyinkronkan nilai <jar-file/>elemen dan dependensi transien sebenarnya?

larutan

ketergantungan langsung (redundan?) dan pemfilteran resource

Saya memasukkan properti dan ketergantungan 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>

Sekarang persistence.xmlbersiaplah untuk disaring

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

Dengan dependencyConvergenceaturan tersebut, kami dapat memastikan bahwa my-entities'versinya sama baik secara langsung maupun 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
sumber
0

Tidak selalu dalam semua kasus.

Saya menggunakan Jboss 7.0.8 dan Eclipselink 2.7.0. Dalam kasus saya untuk memuat entitas tanpa menambahkan hal yang sama di persistence.xml, saya menambahkan properti sistem berikut di Jboss Standalone XML:

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

Gandhi
sumber