我正在为 Google App Engine 编写 Java 应用程序。我有两个实体需要建模为双向无主一对一关系:
第一个对象'ContainableObject'
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class ContainableObject {
/*=== Data Model ===*/
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long key;
@Persistent
@Unowned
private Container container;
和第二个“容器”
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Container {
/*=== Data Model ===*/
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long key;
@Persistent
@Unowned
private ContainableObject containable;
Container 可以是空的,也可以包含一个 ContainableObject。一个 ContainableObject 可以在一个 Container 中,可以在 Container 对象之间移动,或者没有 Container。我需要能够从 Container --> ContainableObject 和 ContainableObject --> Container 中获取
我正在使用 v2 的 datanucleus 插件。通过 maven 这个模型运行集成测试效果很好,但是当我尝试通过我的 REST API 访问它时,我遇到了堆栈溢出:
java.lang.StackOverflowError
at java.util.concurrent.FutureTask.<init>(FutureTask.java:45)
at java.util.concurrent.AbstractExecutorService.newTaskFor(AbstractExecutorService.java:72)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:91)
at com.google.appengine.tools.development.ApiProxyLocalImpl$PrivilegedApiAction.run(ApiProxyLocalImpl.java:277)
at com.google.appengine.tools.development.ApiProxyLocalImpl$PrivilegedApiAction.run(ApiProxyLocalImpl.java:262)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.appengine.tools.development.ApiProxyLocalImpl.doAsyncCall(ApiProxyLocalImpl.java:216)
at com.google.appengine.tools.development.ApiProxyLocalImpl.makeAsyncCall(ApiProxyLocalImpl.java:179)
at com.google.apphosting.api.ApiProxy.makeAsyncCall(ApiProxy.java:184)
at com.google.appengine.api.datastore.DatastoreApiHelper.makeAsyncCall(DatastoreApiHelper.java:59)
at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl.doBatchGetBySize(AsyncDatastoreServiceImpl.java:351)
at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl.get(AsyncDatastoreServiceImpl.java:296)
at com.google.appengine.api.datastore.DatastoreServiceImpl$1.runInternal(DatastoreServiceImpl.java:78)
at com.google.appengine.api.datastore.DatastoreServiceImpl$1.runInternal(DatastoreServiceImpl.java:75)
at com.google.appengine.api.datastore.TransactionRunner.runInTransaction(TransactionRunner.java:31)
at com.google.appengine.api.datastore.DatastoreServiceImpl.get(DatastoreServiceImpl.java:75)
at com.google.appengine.api.datastore.DatastoreServiceImpl.get(DatastoreServiceImpl.java:62)
at com.google.appengine.datanucleus.WrappedDatastoreService.get(WrappedDatastoreService.java:60)
at com.google.appengine.datanucleus.FetchFieldManager.lookupOneToOneChild(FetchFieldManager.java:426)
at com.google.appengine.datanucleus.FetchFieldManager.fetchRelationField(FetchFieldManager.java:341)
at com.google.appengine.datanucleus.FetchFieldManager.fetchObjectField(FetchFieldManager.java:248)
at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:2228)
at com.whatever.ContainableObject.jdoReplaceField(ContainableObject.java)
at com.whatever.ContainableObject.jdoReplaceFields(ContainableObject.java)
at org.datanucleus.state.JDOStateManager.replaceNonLoadedFields(JDOStateManager.java:1988)
at com.google.appengine.datanucleus.EntityUtils$1.fetchNonLoadedFields(EntityUtils.java:976)
at org.datanucleus.ObjectManagerImpl.findObject(ObjectManagerImpl.java:2857)
at com.google.appengine.datanucleus.EntityUtils.entityToPojo(EntityUtils.java:1013)
at com.google.appengine.datanucleus.FetchFieldManager.lookupOneToOneChild(FetchFieldManager.java:427)
at com.google.appengine.datanucleus.FetchFieldManager.fetchRelationField(FetchFieldManager.java:341)
at com.google.appengine.datanucleus.FetchFieldManager.fetchObjectField(FetchFieldManager.java:248)
at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:2228)
at com.whatever.Container.jdoReplaceField(Container.java)
at com.whatever.Container.jdoReplaceFields(Container.java)
at org.datanucleus.state.JDOStateManager.replaceNonLoadedFields(JDOStateManager.java:1988)
at com.google.appengine.datanucleus.EntityUtils$1.fetchNonLoadedFields(EntityUtils.java:976)
at org.datanucleus.ObjectManagerImpl.findObject(ObjectManagerImpl.java:2857)
at com.google.appengine.datanucleus.EntityUtils.entityToPojo(EntityUtils.java:1013)
at com.google.appengine.datanucleus.FetchFieldManager.lookupOneToOneChild(FetchFieldManager.java:427)
at com.google.appengine.datanucleus.FetchFieldManager.fetchRelationField(FetchFieldManager.java:341)
at com.google.appengine.datanucleus.FetchFieldManager.fetchObjectField(FetchFieldManager.java:248)
at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:2228)
at com.whatever.ContainableObject.jdoReplaceField(ContainableObject.java)
at com.whatever.ContainableObject.jdoReplaceFields(ContainableObject.java)
at org.datanucleus.state.JDOStateManager.replaceNonLoadedFields(JDOStateManager.java:1988)
at com.google.appengine.datanucleus.EntityUtils$1.fetchNonLoadedFields(EntityUtils.java:976)
at org.datanucleus.ObjectManagerImpl.findObject(ObjectManagerImpl.java:2857)
at com.google.appengine.datanucleus.EntityUtils.entityToPojo(EntityUtils.java:1013)
at com.google.appengine.datanucleus.FetchFieldManager.lookupOneToOneChild(FetchFieldManager.java:427)
at com.google.appengine.datanucleus.FetchFieldManager.fetchRelationField(FetchFieldManager.java:341)
at com.google.appengine.datanucleus.FetchFieldManager.fetchObjectField(FetchFieldManager.java:248)
at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:2228)
at com.whatever.Container.jdoReplaceField(Container.java)
at com.whatever.Container.jdoReplaceFields(Container.java)
at org.datanucleus.state.JDOStateManager.replaceNonLoadedFields(JDOStateManager.java:1988)
at com.google.appengine.datanucleus.EntityUtils$1.fetchNonLoadedFields(EntityUtils.java:976)
这是建模的错误方法,还是我发现了 AppEngine 错误?