Reputation: 18741
I'm creating a web application in Google App Engine with JDO and I get a JDOFatalUserException
:
javax.jdo.JDOFatalUserException: Detected attempt to establish User(15) as the
parent of SessionToken("VALID_USER_TOKEN") but the entity identified
by SessionToken("VALID_USER_TOKEN") has already been persisted
without a parent. A parent cannot be established or changed once an
object has been persisted.
I have the class User, which has a SessionToken. I want to store both User and a SessionToken in the Datastore. The User key is generated automatically, while the SessionToken key is generated by me.
@PersistenceCapable
public class User {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent
private SessionToken sessionToken;
//getters and setters...
}
And:
@PersistenceCapable
public class SessionToken {
@PrimaryKey
private Key token;
public SessionToken(Key token) {
this.token = token;
}
//getters and setters...
}
Then I want to create a user, so I do:
PersistenceManager pm = PMF.get().getPersistenceManager();
User user = new User();
Key key = KeyFactory.createKey(SessionToken.class.getSimpleName(),
"VALID_USER_TOKEN");
user.setSessionToken(new SessionToken(key));
try {
pm.makePersistent(user);
} finally {
pm.close();
}
Here is the full exception dump:
javax.jdo.JDOFatalUserException: Detected attempt to establish User(15) as the parent of SessionToken("VALID_USER_TOKEN") but the entity identified by SessionToken("VALID_USER_TOKEN") has already been persisted without a parent. A parent cannot be established or changed once an object has been persisted.
at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:498)
at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:736)
at org.datanucleus.api.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:756)
at com.mockgaeapp.UsersEndpoint.register(UsersEndpoint.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:115)
at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:239)
at com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:161)
at com.google.api.server.spi.SystemServiceServlet.doPost(SystemServiceServlet.java:120)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:123)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:61)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:97)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:409)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
I don't understand the error because I don't persist the SessionToken object before persisting the User...
What does this Exception mean?
Upvotes: 1
Views: 817
Reputation: 3436
Your code tells JDO to have 'owned' relationship between the User
and SessionToken
objects, where the child entity is supposed to have parent's key as its parent (in the datastore terminology), while you explicitly set the key without the parent.
Please try using 'unowned' relationship.
Upvotes: 2