No Persistence provider for EntityManager named ... - Hibernate 3.5.2 + JPA2

5 respostas
jweyrich

Buenas!

Este post será um pouco longo, mas acredito que outras pessoas poderão se beneficiar, visto que o problema é (bem?) conhecido.

Eis o problema:

javax.persistence.PersistenceException: No Persistence provider for EntityManager named minha_unit
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
at company.EMF.initialize(EMF.java:47)
at company.EMF.get(EMF.java:57)

Essa exception foi reportada diversas vezes em vários sites/forums/etc, inclusive aqui. Mas as soluções mencionadas não funcionaram para mim.

Ela ocorre quando invoco Persistence.createEntityManagerFactory(). Essa funcão é invocada no primeiro RPC que necessita acesso ao DB. Neste ponto, eu tento criar o EntityManagerFactory para minha persistent unit (configurada no persistence.xml), mas isto gera a exception.

Resumidamente, meu projeto utiliza:

- GWT 2.0.3
- Hibernate 3.5.2 Final
- JPA2 -- finalmente padronizaram as configs!
- MySQL

Estou usando Eclipse com o plugin do GWT, e rodando no Jetty built-in.
Abaixo seguem os dados necessários (faltou algo?) para que alguém possa me dar uma pista.

.classpath
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" path="src"/>
	<classpathentry kind="src" output="test-classes" path="test"/>
	<classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/gwt-servlet.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/slf4j-1.6.0/slf4j-api-1.6.0.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/slf4j-1.6.0/slf4j-log4j12-1.6.0.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/mysql/mysql-connector-java-5.1.6-bin.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/antlr-2.7.6.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/cglib-2.2.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/commons-collections-3.1.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/dom4j-1.6.1.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/hibernate3.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/hibernate-jpa-2.0-api-1.0.0.Final.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/hibernate-entitymanager-3.5.1-Final.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/javassist-3.9.0.GA.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/hibernate-3.5.2-final/jta-1.1.jar"/>
	<classpathentry kind="lib" path="war/WEB-INF/lib/log4j-1.2.16/log4j-1.2.16.jar"/>
	<classpathentry kind="output" path="war/WEB-INF/classes"/>
</classpath>
src/META-INF/persistence.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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"
	version="1.0">
	<persistence-unit name="minha_unit">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		# Removi os <class> para postar aqui
		<properties>
			<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
			<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/meu_db" />
			<property name="javax.persistence.jdbc.user" value="meu_usuario" />
			<property name="javax.persistence.jdbc.password" value="minha_senha" />
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
			<property name="hibernate.show_sql" value="true" />
			<property name="hibernate.format_sql" value="true" />
			<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
			<property name="cache.use_query_cache" value="false" />
			<property name="cache.use_minimal_puts" value="false" />
			<property name="max_fetch_depth" value="3" />
		</properties>
	</persistence-unit>
</persistence>

Como sabem, o Eclipse copia o conteúdo das source-folders para as output-folders (WEB-INF/classes, etc) durante a compilação. Desconfiei que pudesse ser um problema relacionado a cópia dos arquivos "extras", então verifiquei os jars e conteúdo do persistence.xml, mas estão sendo copiados corretamente.

Para piorar o cenário, criei essa classe (notem que é J2SE) de teste, que rodou sem problema algum:
package company;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import company.EMF;

public class Test {
	public static void main(String[] args) {
		EntityManagerFactory factory = EMF.get();
		EntityManager em = factory.createEntityManager();
		em.createQuery("SELECT u FROM User u").getResultList();
	}
}
Se vocês ainda estão se perguntando o que a tal classe EMF faz, removi algumas dezenas de linhas comentadas, e aqui está:
package company;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public final class EMF {
	private static EntityManagerFactory emf;
	private EMF() {}
	public static void initialize(String unit) {
		if (emf == null)
			emf = Persistence.createEntityManagerFactory(unit); // Esta é a linha 47 mostrada na exception
	}
	public static void shutdown() {
		emf.close();
	}
	public static EntityManagerFactory get() {
		if (emf == null)
			initialize("minha_unit");
		return emf;
	}
}

Resumo

O mesmo projeto, com o mesmo classpath, mesmos arquivos e mesma configuração, funciona na aplicação J2SE, mas não funciona quando rodo no servidor. Isso lhes diz algo?

Os 2 ambientes (J2SEe J2EE) tem diferenças, mas se estivesse faltando uma dependência (jar), a aplicação J2SE deveria ter o mesmo problema, concordam?
O mesmo vale para a configuração, exceto as transactions, que não defini no persistence.xml pois o próprio ORM decide de acordo com o ambiente. No caso da aplicação J2SE, ele usa RESOURCE_LOCAL, e J2EE utiliza JTA. Mas isso é irrelevante para este problema, acredito eu.

Aproveitando o post: O jar do hibernate-entitymanager nessa versão 3.5 é realmente necessário? Pessoalmente, acredito que sim, mas neste ponto não parece fazer nenhuma diferença deixá-lo ou removê-lo.

Apesar de não resolver o meu problema, o post mais esclarecedor que encontrei foi ESTE.

Ah sim, obrigado a todos que leram até o fim! :)

5 Respostas

Lucas_Cavalcanti

tenta ver se a pasta META-INF com o arquivo persistence.xml está na pasta WEB-INF/classes do servidor mesmo… sem isso não funciona…

PS: no VRaptor tb é usado o Persistence.createEntityManagerFactory

jweyrich

Verifiquei isto, mas o “deploy” está correto.
Como o projeto não tem praticamente nada, estou rodando no eclipse ainda (na verdade, no Jetty que vem built-in no GWT SDK).

$ find . -name persistence.xml
./src/META-INF/persistence.xml
./war/WEB-INF/classes/META-INF/persistence.xml
$ find . -name persistence.xml | xargs -n2 diff
$

Como pode ver, o conteúdo dos 2 arquivos é idêntico.

A propósito, este é o javadoc que mencionei na mensagem que lhe enviei.

Lucas_Cavalcanti

no seu classpath, vc colocou alguns jars na pasta:

war/WEB-INF/lib/hibernate-3.5.2-final/

mova-os pra pasta war/WEB-INF/lib, ou seja, tire a pasta intermediária

jweyrich

Oh, não creio! O problema era esse. Obrigado Lucas!

Sabes me dizer por que não é possível manter uma estrutura de diretórios no WEB-INF/lib? Considerando o classhpath, achei que não era problema. Parece que os servidores de aplicação ignoram o classpath. Isto é correto?

Lucas_Cavalcanti

nos servidores de aplicação o que vale é o que está dentro do WEB-INF/lib… o .classpath é configuração do eclipse, não tem nada a ver…
e não pode ter estruturas de diretório dentro do WEB-INF/lib

Criado 19 de maio de 2010
Ultima resposta 20 de mai. de 2010
Respostas 5
Participantes 2