语境
我在我的一个基于云的 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 预提交中排除这个测试,以便能够将项目推送到我的仓库中......