В моем проекте (Spring Framework + Google App Engine + DataNucleus + JPA) я получаю следующее исключение при запуске сервера:Как настроить зависимости для DataNucleus AppEngine plugin v3?
WARNING: Nestedin org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/spring/db.xml]: Invocation of init method failed;
nested exception is java.lang.NoSuchMethodError: org.datanucleus.metadata.MetaDataUtils.parsePersistenceFiles(Lorg/datanucleus/plugin/PluginManager;Ljava/lang/String;ZLorg/datanucleus/NucleusContext;)[Lorg/datanucleus/metadata/PersistenceFileMetaData;:
java.lang.NoSuchMethodError: org.datanucleus.metadata.MetaDataUtils.parsePersistenceFiles(Lorg/datanucleus/plugin/PluginManager;Ljava/lang/String;ZLorg/datanucleus/NucleusContext;)[Lorg/datanucleus/metadata/PersistenceFileMetaData;
at org.datanucleus.api.jpa.JPAEntityManagerFactory.<init>(JPAEntityManagerFactory.java:342)
at org.datanucleus.api.jpa.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:91)
Очевидно, что это исключение во время persistence.xml
забросило разбора. Spring пытается вызвать метод MetaDataUtils#parsePersistenceFiles(PluginManager,String,NucleusContext,nucCtx)
, но он отсутствует. Этот метод является частью org.datanucleus:datanucleus-core
. Сначала я подумал, что у меня есть недостающая или дублирующая зависимость где-то. Я выполнил
gradle dependencies
тщательно отсканированный вывод и не нашел ничего подозрительного: только одна версия зависимости.
Согласно документации MetaDataUtils
имеет только один метод: parsePersistenceFiles
public static PersistenceFileMetaData[] parsePersistenceFiles(
PluginManager pluginMgr, String persistenceFilename, boolean validate, ClassLoaderResolver clr);
Если вы наблюдательны, вы, вероятно, заметили, что она отличается в аргументах: есть дополнительный аргумент boolean validate
. Странно, что такого метода нет в любой версии DataNucleus. Почему DataNucleus ищет метод, который даже не существовал? Я не могу это получить.
Помогите DataNucleus и мне найти недостающий способ!
UPDATE
Как Neil Stockton отметил, что это потому, что я использую несовместимые версии DataNucleus-ядра и DataNucleus-Апи-JPA. Но я не знаю правильной комбинации зависимостей. И я начинаю думать, что DataNucleus App Engine Plugin 3.0 в настоящее время не готов к использованию.
Я хочу использовать DataNucleus App Engine Plugin 3.0 из this issue (фиксировано в DataNucleus версиях 3.2.6 и 3.3.3) и потому что мне нужно JPA 2.1 функции (выборка групп/графики сущностей). Модуль Plugin 3.0 для модулей приложений DataNucleus имеет compatible с упомянутыми версиями DataNucleus, но неиздано. Я проверил плагин из SVN, упаковал его и добавил в свой проект как банку (идентичная банка доступна для download, если вы хотите повторить эту настройку самостоятельно).
сборка.Gradle:
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'
dependencies {
// App Engine
compile fileTree(dir: 'libs', include: ['*.jar']) // There is datanucleus-appengine-3.0.0-20140128.jar in libs
appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.19'
compile 'com.google.appengine:appengine-api-1.0-sdk:1.9.19'
// persistence
// App Engine and DataNucleus compatibility:
// https://code.google.com/p/datanucleus-appengine/wiki/Compatibility
compile 'org.eclipse.persistence:javax.persistence:2.1.0'
runtime 'org.datanucleus:datanucleus-core:3.2.15'
compile 'org.datanucleus:datanucleus-api-jpa:3.1.3'
compile 'javax.jdo:jdo-api:3.1'
compile 'org.datanucleus:datanucleus-jodatime:3.2.1'
// Spring Framework
compile("org.springframework:spring-webmvc:4.1.6.RELEASE")
compile ("org.springframework.data:spring-data-jpa:1.8.0.RELEASE")
providedCompile 'javax.annotation:javax.annotation-api:1.2'
compile 'com.google.code.gson:gson:2.3.1'
providedCompile 'org.projectlombok:lombok:1.16.+'
}
appengine {
downloadSdk = true
httpAddress = "0.0.0.0"
}
Spring контекст:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"
default-autowire="byName">
<jpa:repositories base-package="<my.package.name>.repositories" />
<!-- The simplest and the most limited form of JPA deployment -->
<!-- For details see http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-jpa -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="transactions-optional" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
Постоянство блок
<persistence-unit name="transactions-optional">
<provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
<properties>
<property name="datanucleus.NontransactionalRead" value="true" />
<property name="datanucleus.NontransactionalWrite" value="true" />
<property name="datanucleus.ConnectionURL" value="appengine" />
<property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true" />
</properties>
</persistence-unit>
UPDATE:
Если я ставлю DataNucleus-Апи-JPA другой версии на CLASSPATH , например
compile 'org.datanucleus:datanucleus-api-jpa:3.2.2'
я получаю исключение во время повышения:
java.lang.RuntimeException: Unexpected exception
at com.google.appengine.tools.enhancer.Enhancer.execute(Enhancer.java:76)
at com.google.appengine.tools.enhancer.Enhance.<init>(Enhance.java:71)
... 1 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
... 5 more
Caused by: org.datanucleus.exceptions.NucleusException:
Plugin (Bundle) "org.datanucleus.api.jpa" is already registered.
Ensure you dont have multiple JAR versions of the same plugin in the classpath.
The URL "file:/<GRADLE_HOME>/appengine-sdk/appengine-java-sdk-1.9.19/lib/opt/tools/datanucleus/v2/datanucleus-api-jpa-3.1.3.jar" is already registered,
and you are trying to register an identical plugin located at URL "file:/<GRADLE_HOME>/caches/modules-2/files-2.1/org.datanucleus/datanucleus-api-jpa/3.2.2/c24c14634c39b5b9a59dcd379dbb6d93da97f3e7/datanucleus-api-jpa-3.2.2.jar."
at org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:541)
at org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:395)
Из документации:
Приложение Engine Java SDK включает в себя версии 2.x плагин DataNucleus для App Engine. Этот плагин соответствует версии 3.0 платформы доступа DataNucleus, которая позволяет использовать хранилище App Engine через JPA 2.0.
JPA представляет собой стандартный интерфейс для взаимодействия с реляционными базами данных, но хранилище данных App Engine не является реляционной базой данных. В результате есть функции JPA, которые App Engine просто не может поддерживать.
с использованием несовместимых версий DataNucleus-ядра и DataNucleus-Апи-JPA. Spring не делает этот вызов, как показывает ваша трассировка стека, вызывается org.datanucleus.api.jpa.XXX –