When I execute the following code in scala REPL:
javax.persistence.Persistence.createEntityManagerFactory("manager1")
I get
javax.persistence.PersistenceException: No Persistence provider for EntityManager named manager1
The same maven project running Java has no problems (in other words, I believe my dependecies are setup correctly)
Using the remote debugger I found the problem seem to be at PersistenceProviderResolverHolder where it executed the following code:
Enumeration<URL> resources = cl.getResources( "META-INF/services/" + PersistenceProvider.class.getName() )
The returned enumeration has no elements.
When I execute the same REPL session
val cl = classOf[javax.persistence.spi.PersistenceProviderResolverHolder].getClassLoader()
cl.getResources( "META-INF/services/javax.persistence.spi.PersistenceProvider").hasMoreElements
I get “true”
This happens both when using mvn:scala or when using scala directly:
scala -cp "target/dependency/*":target/classes
My dependencies are
[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
The only JPA releated dependency is “org.hibernate:hibernate-entitymanager:3.6.7.Final”
It looks like a classloading problem, but could it be something different?
After some more digging and debugging, I found out that the JPA implementation uses the current tread’s contextual classloader (which in my case is the sun.misc.Launcher$AppClassLoader). That classloader indeed does not include the JPA and Hibernate JARs. (see javax.persistence.spi.PersistenceProviderResolverHolder.PersistenceProviderResolverPerClassLoader#getContextualClassLoader)
Changing the contextual classloader prior to getting the EntityManagerFactory therefore does the trick:
In REPL setting the contextual classloader does not work, it is reset to the application classloader after setting it.
I dkn’t know what the consequences are yet (not sure if all the JPA code will actually work, just did a few tests and seems to work so far).
Also i don’t understand why hibernate would use the contextual classloader and not just the current classloader.