JPA / SCALA没有名为xxx的持久性提供程序?

时间:2011-11-01 07:26:24

标签: scala jpa

当我在scala REPL中执行以下代码时:

javax.persistence.Persistence.createEntityManagerFactory("manager1")

我得到了

javax.persistence.PersistenceException: No Persistence provider for EntityManager named manager1

运行Java的同一个maven项目没有问题(换句话说,我相信我的dependecies设置正确)

使用远程调试器我发现问题似乎是在PersistenceProviderResolverHolder中执行以下代码:

Enumeration<URL> resources = cl.getResources( "META-INF/services/" + PersistenceProvider.class.getName() )

返回的枚举没有元素。

当我执行相同的REPL会话时

val cl = classOf[javax.persistence.spi.PersistenceProviderResolverHolder].getClassLoader()
cl.getResources( "META-INF/services/javax.persistence.spi.PersistenceProvider").hasMoreElements

我得到“真实”

使用mvn:scala或直接使用scala时都会发生这种情况:

scala -cp "target/dependency/*":target/classes

我的依赖是

[INFO] --- maven-dependency-plugin:2.3:tree (default-cli) @ java.jpa.basics ---
[INFO] com.edc4it:java.jpa.basics:jar:1.0
[INFO] +- org.slf4j:slf4j-log4j12:jar:1.6.2:compile
[INFO] |  +- org.slf4j:slf4j-api:jar:1.6.2:compile
[INFO] |  \- log4j:log4j:jar:1.2.16:compile
[INFO] +- mysql:mysql-connector-java:jar:5.1.6:compile
[INFO] +- javassist:javassist:jar:3.9.0.GA:compile
[INFO] +- org.scala-lang:scala-library:jar:2.9.1:compile
[INFO] \- org.hibernate:hibernate-entitymanager:jar:3.6.7.Final:compile
[INFO]    +- org.hibernate:hibernate-core:jar:3.6.7.Final:compile
[INFO]    |  +- antlr:antlr:jar:2.7.6:compile
[INFO]    |  +- commons-collections:commons-collections:jar:3.1:compile
[INFO]    |  +- dom4j:dom4j:jar:1.6.1:compile
[INFO]    |  +- org.hibernate:hibernate-commons-annotations:jar:3.2.0.Final:compile
[INFO]    |  \- javax.transaction:jta:jar:1.1:compile
[INFO]    +- cglib:cglib:jar:2.2:compile
[INFO]    |  \- asm:asm:jar:3.1:compile
[INFO]    \- org.hibernate.javax.persistence:hibernate-jpa-2.0-api:jar:1.0.1.Final:compile

唯一的JPA相关依赖是“org.hibernate:hibernate-entitymanager:3.6.7.Final”

它看起来像一个类加载问题,但它可能是不同的东西吗?

1 个答案:

答案 0 :(得分:1)

经过一些挖掘和调试之后,我发现JPA实现使用了当前胎面的上下文类加载器(在我的例子中是sun.misc.Launcher $ AppClassLoader)。该类加载器确实不包含JPA和Hibernate JAR。 (请参阅javax.persistence.spi.PersistenceProviderResolverHolder.PersistenceProviderResolverPerClassLoader#getContextualClassLoader) 因此,在获取EntityManagerFactory之前更改上下文类加载器可以解决问题:

Thread.currentThread().setContextClassLoader(JPAUtil.class.getClassLoader());
emf =  Persistence.createEntityManagerFactory("manager");

在REPL设置中,上下文类加载器不起作用,在设置后将其重置为应用程序类加载器。

我不知道后果是什么(不确定所有JPA代码是否真的有效,只做了一些测试,似乎到目前为止工作)。 另外我不明白为什么hibernate会使用上下文类加载器而不仅仅是当前的类加载器。