Нужны ли мне элементы <class> в persistence.xml?

110

У меня очень простой файл persistance.xml:

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

и это работает.

Но когда я удаляю <class>элементы, приложение не видит сущностей (все классы помечены @Entity).

Есть ли какой-нибудь автоматический механизм для поиска @Entityклассов?

Михал Мех
источник

Ответы:

78

В файле persistence.xml есть файл, jar-fileкоторый вы можете использовать. Из учебника 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>

Этот файл определяет единицу сохранения состояния с именем OrderManagement, которая использует источник данных с поддержкой JTA jdbc/MyOrderDB. jar-fileИ classэлементы задают управляемую персистентность классов: классы сущностей, встраиваемые классы и отображенный суперкласс. В jar-fileэлементе определяет файлы JAR, которые видны упакованная инерционность единицы , которые содержат управляемую сохранение классов, в то время как classэлемент явно имена удались живучесть классов.

В случае Hibernate взгляните на Chapter2. Установка и настройка также для более подробной информации.

РЕДАКТИРОВАТЬ: На самом деле, если вы не возражаете против несоответствия спецификации, Hibernate поддерживает автоматическое обнаружение даже в Java SE. Для этого добавьте 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>
Паскаль Тивент
источник
13
Понятно, но сущности (@Entity) находятся в отдельном проекте Maven, поэтому имя jar-файла может меняться при каждой сборке. Я ищу что-нибудь для сканирования в конкретном пакете или пути к классам. Мне просто лень вводить много-много элементов <class> в файл persistence.xml.
Michał Mech
На каждой сборке ?! Я даже не буду спрашивать, почему, но ... вы можете использовать фильтрацию, чтобы решить эту проблему.
Паскаль Тивент,
Не все точно, но я хочу быть устойчивым к изменениям.
Michał Mech
5
Я знаю, что это древняя ветка, но взгляните на плагин jpa-maven-plugin .
Laird Nelson
Вы можете использовать элемент <mapping-file> (который содержит список сущностей) в persistence.xml, чтобы вы могли сохранить то же имя используемых файлов и интегрировать их в сборку связанных jar-файлов.
med_alpa
44

В среде Java SE по спецификации вы должны указать все классы, как вы это сделали:

Список всех именованных классов управляемой сохраняемости должен быть указан в средах Java SE для обеспечения переносимости.

и

Если не предполагается, что аннотированные классы сохраняемости, содержащиеся в корне блока сохраняемости, будут включены в блок сохраняемости, следует использовать элемент exclude-unlisted-classes. Элемент exclude-unlisted-classes не предназначен для использования в средах Java SE.

(JSR-000220 6.2.1.6)

В средах Java EE этого делать не нужно, поскольку провайдер сканирует для вас аннотации.

Неофициально можно попробовать установить <exclude-unlisted-classes>false</exclude-unlisted-classes>в своем persistence.xml. По умолчанию этот параметр установлен falseв EE и trueSE. Оба EclipseLink и Toplink поддерживает это, насколько я могу сказать. Но вы не должны полагаться на его работу в SE, согласно спецификации, как указано выше.

Вы можете ПОПРОБОВАТЬ следующее (может работать или не работать в 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>не работал с WildFly 8.2.1.Final + Hibernate 4.3.7
Андреас Дитрих
12

Нужны ли мне элементы класса в persistence.xml?

Нет, не обязательно. Вот как это делается в Eclipse (проверено Кеплером):

Щелкните проект правой кнопкой мыши, выберите " Свойства" , выберите " JPA" и в разделе " Управление классами сохраняемости" отметьте " Автоматически обнаруживать аннотированные классы" .

введите описание изображения здесь

аббас
источник
9
Зачем голосовать за? OP даже не упоминает Eclipse, и этот ответ не показывает, что эта функция Eclipse делает под капотом, чтобы можно было сделать это без IDE.
Артем Новиков
2
@ Артем Новиков: Я считаю это суровым, поскольку часто вопрос возникает из-за разных условий, и здесь мы хотим помочь или дать полезные советы! (как для меня) Это полезно, поскольку Eclipse - это обычная среда IDE для подобной разработки, и внутренняя часть не так важна, но я предполагаю, что она будет включать все соответствующие проекты рабочей области (например, мой проект зависит от этого).
Андреас Дитрих
stackoverflow.com/questions/17951297/… хороший трюк, но, по-видимому, он работает, только если сущности попадают в тот же загрузчик классов, что и persistence.xml
Пьерлуиджи Вернетто
@abbas Пожалуйста, покажите, persistence.xmlчто генерирует Eclipse.
Frans
12

Для тех, кто использует JPA в Spring, начиная с версии 3.1, вы можете установить packagesToScanсвойство в разделе LocalContainerEntityManagerFactoryBeanи полностью избавиться от persistence.xml.

Вот подноготная

Кристофер Янг
источник
Сработало у меня! Сценарий был spring 4 + hibernate + jpa2 + maven. Тестирование JUnit не нашло мои сущности, но с этой настройкой оно выполнило свою работу.
Сб,
8

Вы можете jar-fileуказать путь элемента к папке со скомпилированными классами. Например, я добавил что-то подобное, когда готовил persistence.xml к некоторым интеграционным тестам:

 <jar-file>file:../target/classes</jar-file>
Арек Тржепач
источник
Это то, что я искал!
xtian
Также работает с EclipseLink!
Bombe
8

для JPA 2+ это трюк

 <jar-file></jar-file>

сканировать все банки на войне на предмет аннотированных классов @Entity

eriskooo
источник
2
у вас есть дополнительная информация об этом? это срабатывает случайно или это написано в спецификации? Это зависит от реализации?
Маркус
сканер находится в классе, расширяющем AbstractScannerImpl, спящий режим - не знаю, ошибка это или особенность, извините
eriskooo
1
В Java SE с Hibernate 5.1.2.Final это решение не работает. Hibernate ожидает имя файла jar ( java.lang.IllegalArgumentException: Unable to visit JAR file:).
Стефан
1
работает! :) с WildFly 8.2.1.Final + Hibernate 4.3.7.Final
Андреас Дитрих
Спасибо, человек, много искал, и это лучшее решение из доступных. Wildfly10 + Hibernate 5.0.7 работает.
boutta
7

Hibernate не поддерживает <exclude-unlisted-classes>false</exclude-unlisted-classes>SE (другой плакат упомянул, что это работает с TopLink и EclipseLink).

Существуют инструменты, которые автоматически создают список классов в persistence.xml, например, мастер импорта схемы базы данных в IntelliJ. После того, как у вас есть начальные классы вашего проекта в persistence.xml, должно быть легко добавлять / удалять отдельные классы вручную по мере продвижения вашего проекта.

Чак Стефански
источник
Автоматическое обнаружение сущностей в Java SE просто не является частью JPA. Приложения, использующие это, не переносимы.
Паскаль Тивент 05
4

Не уверен, что вы делаете что-то похожее на то, что делаю я, но я генерирую загрузку исходного кода java из XSD с использованием JAXB в отдельном компоненте с помощью Maven. Допустим, этот артефакт называется «базовая модель».

Я хотел импортировать этот артефакт, содержащий исходный код java, и запустить спящий режим для всех классов в моем банке артефактов «базовой модели» и не указывать каждый явно. Я добавляю «базовую модель» в качестве зависимости для моего компонента спящего режима, но проблема в том, что тег в persistence.xml позволяет указывать только абсолютные пути.

Способ, которым я это обошел, - это явно скопировать мою зависимость jar «базовой модели» в мой целевой каталог, а также удалить ее версию. Итак, если я создаю свой артефакт «базовая модель», он генерирует «base-model-1.0-SNAPSHOT.jar», шаг копирования ресурсов копирует его как «base-model.jar».

Итак, в вашем pom для компонента гибернации:

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

Затем я вызываю плагин hibernate на следующем этапе «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>

и, наконец, в моем persistence.xml я могу явно указать местоположение банки следующим образом:

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

и добавьте свойство:

<property name="hibernate.archive.autodetection" value="class, hbm"/>
Спенсер Ловеридж
источник
3

Это не решение, а подсказка для тех, кто использует Spring:

Я попытался использовать org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeanс настройкой, persistenceXmlLocationно с этим мне пришлось предоставить <class>элементы (даже если они persistenceXmlLocationтолько что указали META-INF/persistence.xml).

Когда я не использую, persistenceXmlLocationя мог опустить эти <class>элементы.

Итан Лерой
источник
Я использовал persistenceXmlLocationсвойство в своих LocalContainerEntityManagerFactoryBeanнастройках. Но все запросы работают, даже если я опущу <class>элементы. Это приложение Spring / Hibernate / Maven. Но в вашем намеке вы говорите, что «Если не использовать persistenceXmlLocation, я мог бы опустить эти элементы <class>». но для меня все наоборот.
Lucky
@Ethen вы правы, потому что persistenceXmlLocation переопределяет packagesToScan - если вы посмотрите в источниках. Так что не используйте его при использовании packagesToScan.
Артем Новиков
2

Я не уверен, что это решение соответствует спецификации, но думаю, что могу поделиться с другими.

дерево зависимостей

my-entity.jar

Содержит только классы сущностей. Нет META-INF/persistence.xml.

my-services.jar

Зависит от my-entities. Содержит только EJB.

my-resources.jar

Зависит от my-services. Содержит классы ресурсов и META-INF/persistence.xml.

проблемы

  • Как мы можем указать <jar-file/>элемент в my-resourcesкачестве имени артефакта с постфиксом версии временной зависимости?
  • Как мы можем синхронизировать значение <jar-file/>элемента и фактическую временную зависимость?

решение

прямая (избыточная?) зависимость и фильтрация ресурсов

Я помещаю свойство и зависимость 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>

Теперь persistence.xmlприготовьтесь к фильтрации

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

С помощью dependencyConvergenceправила мы можем гарантировать, что my-entities'версия одинакова как для прямой, так и для транзитивной.

<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

Не обязательно во всех случаях.

Я использую Jboss 7.0.8 и Eclipselink 2.7.0. В моем случае для загрузки сущностей без добавления их в persistence.xml я добавил следующее системное свойство в Jboss Standalone XML:

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

Ганди
источник