1

语境

我在我的一个基于云的 java 项目中使用了 JDO 的双向拥有的两个对象之间的一对多关系(就像在App Engine 的文档中描述的那样)。

@PersistenceCapable
public class IndexPage implements Page {

    @Persistent(mappedBy = "index")
    @Order(extensions =
      @Extension(
        vendorName = "datanucleus",
        key = "list-ordering",
        value = "title asc"))
    private List<MotherCategoryPage> motherCategoryPages;

    (...)
}

@PersistenceCapable
public class MotherCategoryPage implements Page {
    private String title;

    @Persistent
    private IndexPage index;

    (...)
}

然后使用以下非常常见的 JDO 代码片段将这些对象存储到 appengine 的数据存储区中:

public void persistPage(Page page) {
    PersistenceManager pm = PMF.get();
    Transaction tx = pm.currentTransaction();
    tx.begin();
    // persist a Page object
    pm.makePersistent(page);
    tx.commit();
    pm.close();
}

我还使用 testNG 实现了一个(非常简单的)单元测试,其中我实例化了 IndexPage 对象和 MotherCategoryPage 对象,并使用上述方法将它们持久化。

问题

这就是问题所在。我的代码在生产环境中运行良好(页面在本地和 App Engine 的服务器上都很好地保留了下来),并且我的单元测试通过 Eclipse 完美运行。但是当它通过 maven 执行时测试失败了!(使用万能插件)

这是万无一失的报告:

"Unexpected error during precommit"
org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:419)
org.datanucleus.jdo.JDOTransaction.commit(JDOTransaction.java:132)
org.datanucleus.store.appengine.jdo.DatastoreJDOTransaction.commit(DatastoreJDOTransaction.java:59)
com.mycompany.PageManager.persistPage(PageManager.java:102)
com.mycompany.pages.PageTest.putPagesIntoDb(PageTest.java:167)
com.mycompany.pages.PageTest.pageTest(PageTest.java:90)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
org.testng.internal.Invoker.invokeMethod(Invoker.java:702)
org.testng.internal.Invoker.invokeTestMethod(Invoker.java:894)
org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1219)
org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
org.testng.TestRunner.privateRun(TestRunner.java:768)
org.testng.TestRunner.run(TestRunner.java:617)
org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
org.testng.SuiteRunner.run(SuiteRunner.java:240)
org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:87)
org.testng.TestNG.runSuitesSequentially(TestNG.java:1188)
org.testng.TestNG.runSuitesLocally(TestNG.java:1113)
org.testng.TestNG.run(TestNG.java:1025)
org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:177)
org.apache.maven.surefire.testng.TestNGXmlTestSuite.execute(TestNGXmlTestSuite.java:92)
org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:105)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:103)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)

NestedThrowablesStackTrace:
com.google.apphosting.api.ApiProxy$UnknownException: An error occurred for the API request datastore_v3.RunQuery().
at     com.google.appengine.tools.development.ApiProxyLocalImpl$AsyncApiCall.callInternal(ApiProxyLocalImpl.java:518)
at     com.google.appengine.tools.development.ApiProxyLocalImpl$AsyncApiCall.call(ApiProxyLocalImpl.java:452)
at     com.google.appengine.tools.development.ApiProxyLocalImpl$AsyncApiCall.call(ApiProxyLocalImpl.java:430)
at java.util.concurrent.Executors$PrivilegedCallable$1.run(Executors.java:463)
at java.security.AccessController.doPrivileged(Native Method)
at java.util.concurrent.Executors$PrivilegedCallable.call(Executors.java:460)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at     java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NoClassDefFoundError: org/mortbay/xml/XmlParser
at     com.google.appengine.api.datastore.dev.LocalCompositeIndexManager.getCompositeIndicesNode(LocalCompositeIndexManager.java:446)
at     com.google.appengine.api.datastore.dev.LocalCompositeIndexManager.manageIndexFile(LocalCompositeIndexManager.java:247)
at     com.google.appengine.api.datastore.dev.LocalCompositeIndexManager.processQuery(LocalCompositeIndexManager.java:200)
at     com.google.appengine.api.datastore.dev.LocalDatastoreService$9.run(LocalDatastoreService.java:1068)
at java.security.AccessController.doPrivileged(Native Method)
at     com.google.appengine.api.datastore.dev.LocalDatastoreService.runQuery(LocalDatastoreService.java:1065)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at     com.google.appengine.tools.development.ApiProxyLocalImpl$AsyncApiCall.callInternal(ApiProxyLocalImpl.java:498)
... 10 more

换句话说,错误发生在提交更改时(上述persistPage方法的第 6 行),并且是由以下原因引起的:

java.lang.NoClassDefFoundError: org/mortbay/xml/XmlParser

知道发生了什么吗?这不是一个主要问题,但我必须从 maven 预提交中排除这个测试,以便能够将项目推送到我的仓库中......

4

1 回答 1

0

因此,对于 Maven,它没有 Mortbay 的 XMLParser 所需的所有依赖项(GAE 索引过程使用它 - 所以与持久性无关,但更多的 AppEngine 内部),并且在其他环境中它使用其他一些 XML 解析器,或者有那些必需的部门。因此,调试 CLASSPATH 中的 jar 以及 Maven 为您包含的内容并查看差异。

于 2013-01-25T18:35:31.897 回答