3
votes

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:415) 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.

3
You'll need to show us the error message, as we don't have magical powers to see your screen. ;) - Gregg
You must be more specific about where and what error message are you getting. - jjczopek
sorry, I posted the error message now :) - ryuujin

3 Answers

1
votes

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

0
votes

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.

0
votes

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)