В моем проекте (Spring Framework + Google App Engine + DataNucleus + JPA) я получаю следующее исключение при запуске сервера:
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 и мне найти недостающий метод!
ОБНОВЛЕНИЕ
Как указал Нил Стоктон, это связано с тем, что я использую непоследовательный версии datanucleus-core и datanucleus-api-jpa. Но я не знаю правильную комбинацию зависимостей. И я начинаю думать, что DataNucleus App Engine Plugin 3.0 в настоящее время не готов к использованию.
Я хочу использовать подключаемый модуль DataNucleus App Engine 3.0 из-за этого проблема (исправлена в версиях DataNucleus 3.2.6 и 3.3.3) и потому, что мне нужны функции JPA 2.1 (выборка групп/графиков сущностей). Подключаемый модуль DataNucleus App Engine 3.0 совместим с указанными версиями DataNucleus, но неизданный. Я проверил плагин из SVN, упаковал его и добавил в свой проект как jar (идентичный jar доступен для скачать, если вы хотите повторить эту настройку самостоятельно).
построить.градле:
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"
}
Весенний контекст:
<?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>
ОБНОВЛЕНИЕ:
Если я помещу datanucleus-api-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)
Из документации:
Java SDK для App Engine включает версию 2.x подключаемого модуля DataNucleus для App Engine. Этот подключаемый модуль соответствует версии 3.0 платформы DataNucleus Access, которая позволяет использовать хранилище данных App Engine через JPA 2.0.
JPA представляет собой стандартный интерфейс для взаимодействия с реляционными базами данных, но хранилище данных App Engine не является реляционной базой данных. . В результате есть функции JPA, которые App Engine просто не поддерживает.