В JPA / SCALA нет поставщика сохраняемости с именем xxx?

#scala #jpa

#scala #jpa

Вопрос:

Когда я выполняю следующий код в scala REPL:

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

Я получаю

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

Тот же проект maven, в котором работает Java, не имеет проблем (другими словами, я считаю, что мои зависимости настроены правильно)

Используя удаленный отладчик, я обнаружил, что проблема, похоже, связана с 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
 

Я получаю «true»

Это происходит как при использовании 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:

После еще некоторых поисков и отладки я обнаружил, что реализация 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 будет использовать контекстный загрузчик классов, а не только текущий загрузчик классов.