views:

1740

answers:

4

I try to perform testing on one-to-many unidirectional mapping for grails application on google app engine (GAE) using JPA. The one-to-many unidirectional mapping I attempt to define is between User and Role class. Unfortunately, I am stuck. Just curious is there any developer out there able to make it work successfully.

Following is my development environment:

  • Windows XP Professional
  • App Engine SDK 1.2.2
  • Grails 1.1.1
  • Plugins used: app-engine 0.8.3, gorm-jpa 0.5

The source code located at:

The complete errors stack trace is here:

 [java] Sep 4, 2009 2:08:42 AM com.google.apphosting.utils.jetty.JettyLogger warn
 [java] WARNING: Failed startup of context com.google.apphosting.utils.jetty.DevAppEngineWebAppContext@1ebd75b{/,C:\Documents and Settings\limcheekin\.grails\1.1.1\projects\one2many\stage}
 [java] org.springframework.beans.factory.access.BootstrapException: Error executing bootstraps; nested exception is org.codehaus.groovy.runtime.InvokerInvocationException: org.springframework.orm.jpa.JpaSystemException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"; nested exception is javax.persistence.PersistenceException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"
 [java]     at org.codehaus.groovy.grails.web.context.GrailsContextLoader.createWebApplicationContext(GrailsContextLoader.java:74)
 [java]     at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
 [java]     at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
 [java]     at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:530)
 [java]     at org.mortbay.jetty.servlet.Context.startContext(Context.java:135)
 [java]     at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1218)
 [java]     at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:500)
 [java]     at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
 [java]     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
 [java]     at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:117)
 [java]     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
 [java]     at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:117)
 [java]     at org.mortbay.jetty.Server.doStart(Server.java:217)
 [java]     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
 [java]     at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:152)
 [java]     at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:116)
 [java]     at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:218)
 [java]     at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:162)
 [java]     at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)
 [java]     at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113)
 [java]     at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89)
 [java] Caused by: org.codehaus.groovy.runtime.InvokerInvocationException: org.springframework.orm.jpa.JpaSystemException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"; nested exception is javax.persistence. PersistenceException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"
 [java]     ... 7 more
 [java] Caused by: org.springframework.orm.jpa.JpaSystemException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"; nested exception is javax.persistence.PersistenceException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"
 [java]     at org.grails.jpa.JpaPluginSupport$__clinit__closure3_closure6_closure11_closure38.doCall(JpaPluginSupport.groovy:452)
 [java]     at BootStrap$_closure1.doCall(BootStrap.groovy:13)
 [java]     ... 7 more
 [java] Caused by: javax.persistence.PersistenceException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"
 [java]     at org.datanucleus.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:264)
 [java]     at org.datanucleus.jpa.EntityTransactionImpl.commit(EntityTransactionImpl.java:122)
 [java]     ... 9 more
 [java] Caused by: org.datanucleus.exceptions.NucleusUserException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"
 [java]     at org.datanucleus.store.mapped.scostore.FKSetStore.<init>(FKSetStore.java:184)
 [java]     at org.datanucleus.store.appengine.DatastoreFKSetStore.<init>(DatastoreFKSetStore.java:38)
 [java]     at org.datanucleus.store.appengine.DatastoreManager.newFKSetStore(DatastoreManager.java:353)
 [java]     at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForCollection(MappedStoreManager.java:734)
 [java]     at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForField(MappedStoreManager.java:646)
 [java]     at org.datanucleus.sco.backed.HashSet.<init>(HashSet.java:102)
 [java]     at org.datanucleus.util.ClassUtils.newInstance(ClassUtils.java:94)
 [java]     at org.datanucleus.sco.SCOUtils.newSCOInstance(SCOUtils.java:164)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.wrapSCOField(JDOStateManagerImpl.java:3040)
 [java]     at org.datanucleus.store.fieldmanager.LoadFieldManager.internalFetchObjectField(LoadFieldManager.java:92)
 [java]     at org.datanucleus.store.fieldmanager.AbstractFetchFieldManager.fetchObjectField(AbstractFetchFieldManager.java:104)
 [java]     at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:1197)
 [java]     at com.vobject.grailsfuse.User.jdoReplaceField(User.groovy)
 [java]     at com.vobject.grailsfuse.User.jdoReplaceFields(User.groovy)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2772)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2791)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.loadFieldsInFetchPlan(JDOStateManagerImpl.java:1610)
 [java]     at org.datanucleus.ObjectManagerImpl.performDetachAllOnCommitPreparation(ObjectManagerImpl.java:3192)
 [java]     at org.datanucleus.ObjectManagerImpl.preCommit(ObjectManagerImpl.java:2931)
 [java]     at org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:369)
 [java]     at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:256)
 [java]     at org.datanucleus.jpa.EntityTransactionImpl.commit(EntityTransactionImpl.java:104)
 [java]     ... 9 more
 [java] Sep 4, 2009 2:08:42 AM com.google.apphosting.utils.jetty.JettyLogger warn
 [java] WARNING: Nested in org.springframework.beans.factory.access.BootstrapException: Error executing bootstraps; nested exception is org.codehaus.groovy.runtime.InvokerInvocationException: org.springframework.orm.jpa.JpaSystemException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"; nested exception is javax.persistence.PersistenceException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role":
 [java] Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"
 [java] org.datanucleus.exceptions.NucleusUserException: Class "com.vobject.grailsfuse.User" has collection field "roles" and this has no mapping in the table for the element class "com.vobject.grailsfuse.Role"
 [java]     at org.datanucleus.store.mapped.scostore.FKSetStore.<init>(FKSetStore.java:184)
 [java]     at org.datanucleus.store.appengine.DatastoreFKSetStore.<init>(DatastoreFKSetStore.java:38)
 [java]     at org.datanucleus.store.appengine.DatastoreManager.newFKSetStore(DatastoreManager.java:353)
 [java]     at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForCollection(MappedStoreManager.java:734)
 [java]     at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForField(MappedStoreManager.java:646)
 [java]     at org.datanucleus.sco.backed.HashSet.<init>(HashSet.java:102)
 [java]     at org.datanucleus.util.ClassUtils.newInstance(ClassUtils.java:94)
 [java]     at org.datanucleus.sco.SCOUtils.newSCOInstance(SCOUtils.java:164)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.wrapSCOField(JDOStateManagerImpl.java:3040)
 [java]     at org.datanucleus.store.fieldmanager.LoadFieldManager.internalFetchObjectField(LoadFieldManager.java:92)
 [java]     at org.datanucleus.store.fieldmanager.AbstractFetchFieldManager.fetchObjectField(AbstractFetchFieldManager.java:104)
 [java]     at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:1197)
 [java]     at com.vobject.grailsfuse.User.jdoReplaceField(User.groovy)
 [java]     at com.vobject.grailsfuse.User.jdoReplaceFields(User.groovy)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2772)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2791)
 [java]     at org.datanucleus.state.JDOStateManagerImpl.loadFieldsInFetchPlan(JDOStateManagerImpl.java:1610)
 [java]     at org.datanucleus.ObjectManagerImpl.performDetachAllOnCommitPreparation(ObjectManagerImpl.java:3192)
 [java]     at org.datanucleus.ObjectManagerImpl.preCommit(ObjectManagerImpl.java:2931)
 [java]     at org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:369)
 [java]     at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:256)
 [java]     at org.datanucleus.jpa.EntityTransactionImpl.commit(EntityTransactionImpl.java:104)
 [java]     at org.grails.jpa.JpaPluginSupport$__clinit__closure3_closure6_closure11_closure38.doCall(JpaPluginSupport.groovy:452)
 [java]     at BootStrap$_closure1.doCall(BootStrap.groovy:13)
 [java]     at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:152)
 [java]     at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:116)
 [java]     at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:218)
 [java]     at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:162)
 [java]     at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)
 [java]     at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113)
 [java]     at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89)

Please advice. See whether you have any idea on what went wrong…

Thanks.

A: 

Looks like the problem is that you don't have a User on the Role since you'll need to specify the mappedBy on the collection I think.

@OneToMany(mappedBy="user",fetch=FetchType.EAGER)
Set<Role> roles

Also you don't really need the join table stuff since you aren't really working with tables in app-engine. In essence the role will exist under the user entity.

Hope that helps :)

Philip Dodds
oh and remember to add a user field to the Role class
Philip Dodds
Thanks for fast response and helpful advice. I try with your advice by refer to http://www.java2s.com/Code/Java/JPA/OneToManyMappingWithMappedByToremoveMappingTable.htmBut I face error below while access to role/list page.Error Cause:org.datanucleus.exceptions.NucleusUserException: Field com.vobject.grailsfuse.Role.user should be able to provide a reference to its parent but the entity does not have a parent. Did you perhaps try to establish an instance of com.vobject.grailsfuse.Role as the child of an instance of com.vobject.grailsfuse.User after the child had already been persisted?
limcheekin
The latest source code located at:http://rapidshare.com/files/275893205/one2many.zip.html
limcheekin
A: 

FYI, I had managed to implement one-to-many relationship using "Unowned One-to-Many Relationships", please refer to http://code.google.com/appengine/docs/java/datastore/relationships.html#Unowned%5FRelationships for more information.

Thanks for kindly help so far.

limcheekin
A: 

Dear Philip,

I had implemented the outcome above and stark security into a project called grailsfuse that intended to run on google appengine with custom authentication.

You can access the application at URL below:
grailsfuse.appspot.com

The code is developed using App Engine SDK 1.2.5. You can access the URL below for complete source code:
https://vobject.svn.sourceforge.net/svnroot/vobject/grails/grailsfuse/trunk

Plugins used:
app-engine 0.8.3, gorm-jpa 0.5, stark-security 0.4.2

Please take note that after you install gorm-jpa plugin to the project, you need to apply the fix of URL below to ensure the login screen is working properly:
jira.codehaus.org/browse/GRAILSPLUGINS-1366

Working features:
Unowned One-to-Many Relationships between User and Role

Outstanding Issue:
While execute in app-engine, unable to access to appropriate URL (included /index.gsp, **/create, **/update, **/delete, etc) even after login successfully, suspect something wrong with URL redirection.

Any idea for the outstanding issues above?

Thanks.

limcheekin
A: 

Hi,

For the update, I released appengine-gorm plugin to grails plugin repository, the motivation I wrote this plugin to support batch insert operation. As I am unable to make the one-to-many relationship by using annotation (@OneToMany) working in Google App Engine after so many attempts, I decided to manage the relationship manually instead of using the mapping. However, while I attempt to save the objects in the many side of the one-to-many relationship, I am facing request timeout of google app engine. Then, I find out that the low level API of datastore support persist many objects in one API call, so there is the born of this plugin. Hopefully, it is benefit you and others.

Lastly, I managed make the one-to-many relationship working manually and without the mapping. Please look at live demo app called GrailsFuse at http://grailsfuse.vobject.com/.

I welcome your feedback and comments. Please feel free to drop me an email at limcheekin at vobject dot com.

Thanks.

limcheekin