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.
<?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>
<?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();
}
}
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! :)