我在我的一个基于云的java中使用了两个对象之间的JDO的双向拥有的一对多关系(就像在App Engine's doc中描述的那样)项目
@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执行时测试失败了!(使用surefire插件)
这是万无一失的报告:
"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 pre-commit中排除,以便能够在我的回购中推送项目......
答案 0 :(得分:0)
因此,对于Maven,它不具备Mortbay的XMLParser所需的所有依赖关系(由GAE索引进程使用 - 因此与持久性无关,而是更多的AppEngine内部),而在其他环境中它使用其他一些XML解析器,或具有那些必需的deps。因此,调试CLASSPATH中的jar以及Maven包含的内容并查看差异。