Как настроить зависимости для плагина DataNucleus AppEngine v3?

В моем проекте (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 ищет метод, которого даже не существовало? Я не могу понять.

Dora
Пожалуйста, помогите 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 просто не поддерживает.


comment
использование несовместимых версий datanucleus-core и datanucleus-api-jpa. Spring не выполняет этот вызов, как показывает ваша трассировка стека, вызываемый org.datanucleus.api.jpa.XXX   -  person Neil Stockton    schedule 23.04.2015


Ответы (1)


Простой факт заключается в том, что вы должны использовать согласованные версии различных jar-файлов. Если вы используете Google «datanucleus-appengine» v3.0 (SVN), вам НЕОБХОДИМО иметь проект DataNucleus «datanucleus-core», «datanucleus-api-jpa» v3.2.x (или 3.3.x из datanucleus-api-jpa). ) и никаких других версий. Если вы получите сообщение о

Плагин (Bundle) "org.datanucleus.api.jpa" уже зарегистрирован.

тогда у вас есть несколько версий этого плагина в CLASSPATH, и вы должны ИСПРАВИТЬ свой CLASSPATH (просто распечатайте то, что находится в CLASSPATH, и он скажет вам... что-то вроде System.getProperty("java.class.path")).

В вашем случае у вас есть

файл://appengine-sdk/appengine-java-sdk-1.9.19/lib/opt/tools/datanucleus/v2/datanucleus-api-jpa-3.1.3.jar

и

файл://кеши/модули-2/файлы-2.1/org.datanucleus/datanucleus-api-jpa/3.2.2/c24c14634c39b5b9a59dcd379dbb6d93da97f3e7/datanucleus-api-jpa-3.2.2.jar

так что избавься от первого

person Neil Stockton    schedule 01.05.2015
comment
и если это не дает успеха, то нормально говорить, что не работает, когда вы это делаете. - person Neil Stockton; 16.05.2015