Eu preciso de elementos <class> em persistence.xml?


110

Tenho um arquivo persistance.xml muito simples:

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

Mas quando eu removo os <class>elementos, o aplicativo não vê entidades (todas as classes são anotadas com @Entity).

Existe algum mecanismo automático para fazer a varredura de @Entityclasses?

Respostas:


78

O persistence.xml tem um jar-fileque você pode usar. Do tutorial do 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>

Este arquivo define uma unidade de persistência chamada OrderManagement, que usa uma fonte de dados compatível com JTA jdbc/MyOrderDB. Os elementos jar-filee classespecificam classes de persistência gerenciadas: classes de entidade, classes integráveis ​​e superclasses mapeadas. O jar-fileelemento especifica arquivos JAR que são visíveis para a unidade de persistência empacotada que contém classes de persistência gerenciadas, enquanto o classelemento nomeia explicitamente as classes de persistência gerenciadas.

No caso do Hibernate, dê uma olhada no Capítulo2. Instalação e configuração também para mais detalhes.

EDIT: Na verdade, se você não se importa em não ser compatível com as especificações, o Hibernate oferece suporte à detecção automática, mesmo em Java SE. Para fazer isso, adicione a hibernate.archive.autodetectionpropriedade:

<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
Entendo, mas as entidades (@Entity) estão em projetos Maven separados, então o nome do arquivo jar pode mudar em cada compilação. Estou procurando algo para digitalizar tudo em um pacote específico ou classpath. Estou com preguiça de digitar muitos, muitos elementos <class> no arquivo persistence.xml.
Michał Mech

Em cada construção ?! Eu nem vou perguntar por que, mas ... você poderia usar a filtragem para resolver isso.
Pascal Thivent

Nem todo mundo exatamente, mas quero ser resistente às mudanças.
Michał Mech

5
Tópico antigo, eu sei, mas dê uma olhada no plugin jpa-maven .
Laird Nelson

Você pode usar o elemento <mapping-file> (que contém a lista das entidades) em persistence.xml, para que possa manter o mesmo nome dos arquivos usados ​​e integrá-los na construção dos jars referenciados.
med_alpa

44

No ambiente Java SE, por especificação, você deve especificar todas as classes como fez:

Uma lista de todas as classes de persistência gerenciadas nomeadas deve ser especificada em ambientes Java SE para garantir a portabilidade

e

Se não for pretendido que as classes de persistência anotadas contidas na raiz da unidade de persistência sejam incluídas na unidade de persistência, o elemento exclude-unlisted-classes deve ser usado. O elemento exclude-unlisted-classes não se destina ao uso em ambientes Java SE.

(JSR-000220 6.2.1.6)

Em ambientes Java EE, você não precisa fazer isso, pois o provedor procura anotações para você.

Extraoficialmente, você pode tentar definir <exclude-unlisted-classes>false</exclude-unlisted-classes>em seu persistence.xml. Este parâmetro é padronizado falseem EE e trueem SE. Tanto o EclipseLink quanto o Toplink suportam isso, pelo que posso dizer. Mas você não deve confiar que ele funcionará no SE, de acordo com as especificações, conforme declarado acima.

Você pode TENTAR o seguinte (pode ou não funcionar em ambientes 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>não funcionou com WildFly 8.2.1.Final + Hibernate 4.3.7
Andreas Dietrich

12

Eu preciso de elementos de classe em persistence.xml?

Não, você não necessariamente. Aqui está como você faz isso no Eclipse (testado pelo Kepler):

Clique com o botão direito do mouse no projeto, clique em Propriedades , selecione JPA , no tique de gerenciamento de classe de Persistência, Descobrir classes anotadas automaticamente .

insira a descrição da imagem aqui


9
Por que votar positivamente? OP nem mesmo menciona o Eclipse e essa resposta não mostra o que esse recurso do Eclipse faz nos bastidores, de forma que alguém poderia fazer isso sem um IDE.
Artem Novikov

2
@Artem Novikov: Acho isso muito difícil, pois muitas vezes a questão surge de diferentes ambientes e aqui queremos ajudar ou dar dicas que sejam úteis! (como para mim) É útil, pois o Eclipse é um IDE comum para desenvolver assim e nos bastidores não é tão importante, mas acho que incluirá todos os projetos de espaço de trabalho relevantes (por exemplo, meu projeto depende de).
Andreas Dietrich

stackoverflow.com/questions/17951297/… bom truque, mas aparentemente funciona apenas se as entidades terminarem no mesmo classloader que o persistence.xml
Pierluigi Vernetto

@abbas Por favor, mostre o persistence.xmlque o Eclipse gera.
Frans

12

Para aqueles que executam JPA no Spring, da versão 3.1 em diante, você pode definir a packagesToScanpropriedade em LocalContainerEntityManagerFactoryBeane se livrar de persistence.xml completamente.

Aqui está o detalhe


Funcionou para mim! O cenário era spring 4 + hibernate + jpa2 + maven. O teste JUnit não encontrou minhas entidades, mas com essa configuração, fez o trabalho.
Sábado,

8

Você pode fornecer o jar-filecaminho do elemento para uma pasta com classes compiladas. Por exemplo, adicionei algo assim quando preparei persistence.xml para alguns testes de integração:

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

Isso é o que eu estava procurando!
xtian

Funciona com EclipseLink também!
Bombe,

8

para JPA 2+ isso resolve

 <jar-file></jar-file>

escaneie todos os frascos em guerra para classes @Entity anotadas


2
você tem mais informações sobre isso? isso funciona por acidente ou está escrito na especificação? Depende da implementação?
markus de

scanner está em aula estendendo AbstractScannerImpl, hibernar - não
tenho

1
Em Java SE com Hibernate 5.1.2.Final, esta solução não funciona. O Hibernate espera um nome de arquivo jar ( java.lang.IllegalArgumentException: Unable to visit JAR file:).
Stephan

1
trabalho! :) com WildFly 8.2.1.Final + Hibernate 4.3.7.Final
Andreas Dietrich

Cara, pesquisei muito e essa é a solução mais bacana disponível. Wildfly10 + Hibernate 5.0.7 funcionando.
boutta de

7

O Hibernate não é compatível <exclude-unlisted-classes>false</exclude-unlisted-classes>com SE, (outro autor mencionou que isso funciona com TopLink e EclipseLink).

Existem ferramentas que irão gerar automaticamente a lista de classes para persistence.xml, por exemplo, o assistente Import Database Schema no IntelliJ. Depois de obter as classes iniciais do seu projeto em persistence.xml, deve ser simples adicionar / remover classes individuais manualmente à medida que o projeto avança.


A detecção automática de entidades no Java SE simplesmente não faz parte do JPA. Os aplicativos que dependem disso não são portáteis.
Pascal Thivent

4

Não tenho certeza se você está fazendo algo semelhante ao que estou fazendo, mas estou gerando uma carga de fonte java de um XSD usando JAXB em um componente separado usando Maven. Vamos dizer que este artefato é chamado de "modelo base"

Eu queria importar este artefato contendo o código-fonte java e executar o hibernate em todas as classes em meu jar de artefato "modelo base" e não especificar cada uma explicitamente. Estou adicionando "modelo base" como uma dependência para meu componente de hibernação, mas o problema é que a tag em persistence.xml permite apenas que você especifique caminhos absolutos.

A forma como eu contornei isso é copiar minha dependência jar do "modelo base" explicitamente para meu diretório de destino e também remover a versão dele. Portanto, enquanto se eu construir meu artefato "modelo-base", ele gerar "modelo-base-1.0-SNAPSHOT.jar", a etapa de recursos de cópia o copia como "modelo-base.jar".

Portanto, em seu pom para o componente de hibernação:

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

Em seguida, chamo o plug-in de hibernação na próxima fase de "classes de 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, finalmente, em meu persistence.xml, posso definir explicitamente a localização do jar assim:

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

e adicione a propriedade:

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

3

Não é uma solução, mas uma dica para quem usa Spring:

Tentei usar org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeancom configuração, persistenceXmlLocationmas com isso tive que fornecer os <class>elementos (mesmo que o que persistenceXmlLocationacabei de apontar META-INF/persistence.xml).

Quando nãopersistenceXmlLocation estou usando, posso omitir esses <class>elementos.


Usei persistenceXmlLocationpropriedade em minhas LocalContainerEntityManagerFactoryBeanconfigurações. Mas todas as consultas estão funcionando, mesmo se eu omitir os <class>elementos. Está em um aplicativo Spring / Hibernate / Maven. Mas em sua dica você diz que "Quando não estiver usando persistenceXmlLocation, eu poderia omitir esses elementos <class>." mas é o contrário para mim.
Sorte de

@ Ethan você está certo, porque persistenceXmlLocation substitui packagesToScan - se você olhar nas fontes. Portanto, não o use, ao usar packagesToScan.
Artem Novikov

2

Não tenho certeza se esta solução está dentro das especificações, mas acho que posso compartilhar com outras pessoas.

árvore de dependência

my-entity.jar

Contém apenas classes de entidade. Não META-INF/persistence.xml.

my-services.jar

Depende my-entities. Contém apenas EJBs.

my-resources.jar

Depende my-services. Contém classes de recursos e META-INF/persistence.xml.

problemas

  • Como podemos especificar <jar-file/>element in my-resourcescomo o nome do artefato pós-corrigido da versão de uma dependência transitória?
  • Como podemos sincronizar o <jar-file/>valor do elemento e o valor real da dependência transitória?

solução

dependência direta (redundante?) e filtragem de recursos

Eu coloquei uma propriedade e uma dependência em 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>

Agora persistence.xmlprepare-se para ser filtrado

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

Plug-in Maven Enforcer

Com a dependencyConvergenceregra, podemos assegurar que a my-entitiesversão 'é a mesma tanto direta quanto 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

Não necessariamente em todos os casos.

Estou usando Jboss 7.0.8 e Eclipselink 2.7.0. No meu caso, para carregar entidades sem adicionar as mesmas em persistence.xml, adicionei a seguinte propriedade de sistema no Jboss Standalone XML:

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.