Grails Spring Security Plugin - ONE-TO-ONE association with User domain
I'm using Spring Security Plugin to manage membership and authentication in my Grails app.
I'm trying to associate the User domain class with a Profile domain by a one-to-one association.
I added these line on User.groovy:
static hasOne = [userProfile:UserProfile]
static constraints = {
//...
userProfile unique:true
}
and to UserProfile.groovy:
User user
Alas, I had error when invoking UseRole.create(user,role).
There is some best practice on how to obtain the same functionality I'm looking for. In particular, I want to associate any user with one profile object to extend it.
I want then also add one-to-many relations with posts and other table...
Thanks best regards
PS: I obtain this error:
Configuring Spring Security UI ... 2011-03-08 12:18:51,179 [main] ERROR context.GrailsContextLoader - Error executing bootstraps: null java.lang.NullPointerException at $Proxy19.save(Unknown Source) at com.dromedian.xxxxx.security.UserRole.create(UserRole.groovy:32) at com.dromedian.xxxxx.security.UserRole$create.call(Unknown Source) at BootStrap$_closure1.doCall(BootStrap.groovy:20) at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.java:251) at grails.util.Environment.executeForEnvironment(Environment.java:244) at grails.util.Environment.executeForCurrentEnvironment(Environment.java:220) at org.grails.tomcat.TomcatServer.start(TomcatServer.groovy:212) at grails.web.container.EmbeddableServer$start.call(Unknown Source) at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy:158) at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy) at _GrailsSettings_groovy$_run_closure10.doCall(_GrailsSettings_groovy:280) at _GrailsSettings_groovy$_run_closure10.call(_GrailsSettings_groovy) at _GrailsRun_groovy$_run_closure5.doCall(_GrailsRun_groovy:149) at _GrailsRun_groovy$_run_closure5.call(_GrailsRun_groovy) at _GrailsRun_groovy.runInline(_GrailsRun_groovy:116) at _GrailsRun_groovy.this$4$runInline(_GrailsRun_groovy) at _GrailsRun_groovy$_run_closure1.doCall(_GrailsRun_groovy:59) at RunApp$_run_closure1.doCall(RunApp.groovy:33) at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381) at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415) at gant.Gant$_dispatch_closure7.doCall(Gant.groovy) at gant.Gant.withBuildListeners(Gant.groovy:427) at gant.Gant.this$2$withBuildListeners(Gant.groovy) at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source) at gant.Gant.dispatch(Gant.groovy:41开发者_Python百科5) at gant.Gant.this$2$dispatch(Gant.groovy) at gant.Gant.invokeMethod(Gant.groovy) at gant.Gant.executeTargets(Gant.groovy:590) at gant.Gant.executeTargets(Gant.groovy:589) Application context shutting down...
The configuration is:
User.groovy (domain class created by spring security plugin)
static hasOne = [userDetail:UserDetail]
static constraints = {
username blank: false, unique: true
password blank: false
userDetail unique:true
}
UserDetail.groovy
static hasOne = [user:User]
static belongsTo = User
BootStrap.groovy
//TODO temporary added - no for production or persistent db
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true)
def userRole = new Role(authority: 'ROLE_USER').save(flush: true)
String password = springSecurityService.encodePassword('password')
def testUser = new User(username: 'me', enabled: true, password: password)
testUser.save(flush: true)
if(testUser != null){
UserRole.create testUser, adminRole, true
}
If I don't call
UserRole.create testUser, adminRole, true
there is no error. I tried to debug, but I can understand where is the error.
As previously explained, your test user is not saved, since a user profile is required. The save method on the user would have returned null, however, you do not check on that. I usually put a method along those lines in:
def ensureSave(domainObject) {
if(!domainObject.save(flush:true)) {
throw new Exception("not saved successfully: $domainObject");
}
domainObject
}
And then refer to it as follows:
ensureSave(testUser)
or
testUser = ensureSave(new User(...));
HTH
I think you have to set the UserProfile in the constructor. Because you are not providing one, the save() fails, thus giving you the NullPointerException
.
UserDetail profile = new UserDetail()
def testUser = new User(username: 'me', enabled: true, password: password, userdetail: profile)
assert testUser.save()
Asserting over the .save() calls has proven quite useful as often when you change some code in your domain class you're constructors won't work in the bootstrap file if you forget to change them. As grails deals fairly gracefully with that, you get weird errors instead getting the message where it would help you most. By placing the asserts it will halt directly where the problem is.
I just ran into a similar issue...and have deduced this:
Your linked class must explicitly be allowed to be null...that is:
static constraints = {
...
userDetail unique:true, nullable: true
...
}
If you don't do this, the constructor call for your class fails (as others have pointed out, and attempting to create a UserRole on null fails)
精彩评论