Adding UserProfile to User with Grails and Spring Security. Parameter #7 is not set - spring

I'm having trouble extending the Spring Security User class to include a profile class. The profile class is simple and just holds a list of Strings. When I go to run the application, I'm thrown the following error, Parameter 7 is not set:
| Error 2014-03-20 22:33:26,751 [localhost-startStop-1] ERROR util.JDBCExceptionReporter - Parameter "#7" is not set; SQL statement:
insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?) [90012-173]
| Error 2014-03-20 22:33:26,815 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing the application: Hibernate operation: could not insert: [ibm_cd_dashboard.User]; uncategorized SQLException for SQL [insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?)]; SQL state [90012]; error code [90012]; Parameter "#7" is not set; SQL statement:
insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?) [90012-173]; nested exception is org.h2.jdbc.JdbcSQLException: Parameter "#7" is not set; SQL statement:
insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?) [90012-173]
Message: Hibernate operation: could not insert: [ibm_cd_dashboard.User]; uncategorized SQLException for SQL [insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?)]; SQL state [90012]; error code [90012]; Parameter "#7" is not set; SQL statement:
insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?) [90012-173]; nested exception is org.h2.jdbc.JdbcSQLException: Parameter "#7" is not set; SQL statement:
insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?) [90012-173]
Line | Method
->> 28 | ensureSave in BootStrap
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 14 | doCall in BootStrap$_closure1
| 308 | evaluateEnvironmentSpecificBlock in grails.util.Environment
| 301 | executeForEnvironment in ''
| 277 | executeForCurrentEnvironment . . in ''
| 262 | run in java.util.concurrent.FutureTask
| 1145 | runWorker . . . . . . . . . . . in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 744 | run . . . . . . . . . . . . . . in java.lang.Thread
Caused by JdbcSQLException: Parameter "#7" is not set; SQL statement:
insert into user (id, version, account_expired, account_locked, enabled, "password", password_expired, user_profile_id, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?) [90012-173]
->> 331 | getJdbcSQLException in org.h2.message.DbException
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 171 | get in ''
| 148 | get . . . . . . . . . . . . . . in ''
| 80 | checkSet in org.h2.expression.Parameter
| 163 | checkParameters . . . . . . . . in org.h2.command.Prepared
| 78 | update in org.h2.command.CommandContainer
| 235 | executeUpdate . . . . . . . . . in org.h2.command.Command
| 154 | executeUpdateInternal in org.h2.jdbc.JdbcPreparedStatement
| 140 | executeUpdate . . . . . . . . . in ''
| 28 | ensureSave in BootStrap
| 14 | doCall . . . . . . . . . . . . . in BootStrap$_closure1
| 308 | evaluateEnvironmentSpecificBlock in grails.util.Environment
| 301 | executeForEnvironment . . . . . in ''
| 277 | executeForCurrentEnvironment in ''
| 262 | run . . . . . . . . . . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 744 | run in java.lang.Thread
| Error 2014-03-20 22:33:27,071 [Thread-13] ERROR hbm2ddl.SchemaExport - schema export unsuccessful
Message: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-173]
Line | Method
->> 331 | getJdbcSQLException in org.h2.message.DbException
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 171 | get in ''
| 148 | get . . . . . . . . in ''
| 137 | get in ''
| 1413 | checkClosed . . . . in org.h2.jdbc.JdbcConnection
| 1388 | checkClosed in ''
| 428 | getAutoCommit . . . in ''
^ 744 | run in java.lang.Thread
User Profile:
class UserProfile {
static hasOne = [user:User]
static belongsTo = User
static constraints = {
}
static mapping = {
}
List<String> projects
}
User is basically the standard spring class:
class User {
transient springSecurityService
static hasOne = [userProfile:UserProfile]
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints = {
username blank: false, unique: true
password blank: false
userProfile unique:true, nullable: true
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
Bootstrap:
def init = { servletContext ->
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true)
def userRole = new Role(authority: 'ROLE_USER').save(flush: true)
def testUser = new User(username: 'me', password: 'password', userProfile: null)
ensureSave(testUser)
testUser.userProfile = new UserProfile(projects: null, version: null, user: testUser)
ensureSave(testUser)
UserRole.create testUser, adminRole, true
assert User.count() == 1
assert Role.count() == 2
assert UserRole.count() == 1
}
def ensureSave(domainObject) {
if(!domainObject.save(flush:true)) {
throw new Exception("not saved successfully: $domainObject");
}
domainObject
}
Removing the associations between the User and UserProfile class allows the application to run normally. Playing around wiht the code I've also gotten "Parameter #4 is not set". Any help appreciated.

This kind off error usually happens, when you have submitted a null value, for a not-null field. Please check data in your domain objects before save, for null values.
Also please remove static hasOne = [user:User] association from Userprofile. The belongsTo is just fine here.

I was able to successfully resolve this issue using the help of the comments posted by other users. Here is the updated code.
Bootstrap
class BootStrap {
def init = { servletContext ->
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true)
def userRole = new Role(authority: 'ROLE_USER').save(flush: true)
def testUser = new User(username: 'me', password: 'password', userProfile: new UserProfile(projects: null, version: null))
testUser.save(flush: true, failOnError: true)
UserRole.create testUser, adminRole, true
assert User.count() == 1
assert Role.count() == 2
assert UserRole.count() == 1
}
def destroy = {
}
}
UserProfile
class UserProfile {
static belongsTo = [user:User]
static constraints = {
}
static mapping = {
}
List<String> projects
}
User Class:
class User {
transient springSecurityService
static hasOne = [userProfile:UserProfile]
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints = {
username blank: false, unique: true
password blank: false
userProfile unique:true, nullable: true
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}

Related

Grails Login Not Working

I am using Grails 2.4 with spring security
compile "org.grails.plugins:spring-security-core:2.0.0"
The following is my bootstrap.groovy
import com.aarestu.grailstest.Role
import com.aarestu.grailstest.User
import com.aarestu.grailstest.UserRole
class BootStrap {
def init = { servletContext ->
def user = new User(usernmae: 'user', password: 'user').save(flush: true, failOnError: true)
def userSecond = new User(usernmae: 'user2', password: 'user').save(flush: true, failOnError: true)
def admin = new User(usernmae: 'admin', password: 'admin').save(flush: true, failOnError: true)
def userRole = new Role(authority: 'ROLE_USER').save(flush: true, failOnError: true)
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true, failOnError: true)
new UserRole(user: user, role: userRole).save(flush: true, failOnError: true)
new UserRole(user: admin, role: adminRole).save(flush: true, failOnError: true)
}
def destroy = {
}
}
It created 2 entries into the table Role but none of the others.
I then manually created a user in the database and when I try to login with the user it simply doesnt work even though I can view it in the database.
If the
failOnError:true
Is not included then it runs ok but I cannot login, if it is included I get the error included at the very end
I also accounted for the double encoding by modifying my USER controller to include the following
boolean beforeInsertRunOnce = false
boolean beforeUpdateRunOnce = false
Set<Role> getAuthorities() {
UserRole.findAllByUser(this)*.role
}
def beforeInsert() {
if (! beforeInsertRunOnce) {
beforeInsertRunOnce = true
encodePassword()
}
}
def afterInsert() {
beforeInsertRunOnce = false
}
def beforeUpdate() {
if (isDirty('password') && ! beforeUpdateRunOnce ) {
beforeUpdateRunOnce = true
encodePassword()
}
}
def afterUpdate() {
beforeUpdateRunOnce = false
}
Error
Error |
2016-02-09 11:42:58,434 [localhost-startStop-1] ERROR context.GrailsContextLoaderListener - Error initializing the application: Validation Error(s) occurred during save():
- Field error in object 'com.aarestu.grailstest.User' on field 'username': rejected value [null]; codes [com.aarestu.grailstest.User.username.nullable.error.com.aarestu.grailstest.User.username,com.aarestu.grailstest.User.username.nullable.error.username,com .aarestu.grailstest.User.username.nullable.error.java.lang.String,com.aarestu .grailstest.User.username.nullable.error,user.username.nullable.error.com.aar estu.grailstest.User.username,user.username.nullable.error.username,user.user name.nullable.error.java.lang.String,user.username.nullable.error,com.aarestu .grailstest.User.username.nullable.com.aarestu.grailstest.User.username,com.aarestu.grailstest.User.username.nullable.username,com.aarestu.grailstest.User.username.nullable.java.lang.String,com.aarestu.grailstest.User.username.nullable,user.username.nullable.com.aarestu.grailstest.User.username,user.username.nullable.username,user.username.nullable.java.lang.String,user.username.nullable,nullable.com.aarestu.grailstest.User.username,nullable.username,nullable.java.lang.String,nullable]; arguments [username,class com.aarestu.grailstest.User]; default message [Property [{0}] of class [{1}] cannot be null]
Message: Validation Error(s) occurred during save():
- Field error in object 'com.aarestu.grailstest.User' on field 'username': rejected value [null]; codes [com.aarestu.grailstest.User.username.nullable.error.com.aarestu.grailstest.User.username,com.aarestu.grailstest.User.username.nullable.error.username,com .aarestu.grailstest.User.username.nullable.error.java.lang.String,com.aarestu .grailstest.User.username.nullable.error,user.username.nullable.error.com.aarestu.grailstest.User.username,user.username.nullable.error.username,user.username.nullable.error.java.lang.String,user.username.nullable.error,com.aarestu .grailstest.User.username.nullable.com.aarestu.grailstest.User.username,com.aarestu.grailstest.User.username.nullable.username,com.aarestu.grailstest.User .username.nullable.java.lang.String,com.aarestu.grailstest.User.username.nullable,user.username.nullable.com.aarestu.grailstest.User.username,user.username.nullable.username,user.username.nullable.java.lang.String,user.username.nullable,nullable.com.aarestu.grailstest.User.username,nullable.username,nullable.java.lang.String,nullable]; arguments [username,class com.aarestu.grailstest.User]; default message [Property [{0}] of class [{1}] cannot be null]
Line | Method
->> 9 | doCall in BootStrap$_closure1
| 327 | evaluateEnvironmentSpecificBlock in grails.util.Environment
| 320 | executeForEnvironment . . . . . in ''
| 296 | executeForCurrentEnvironment in ''
| 266 | run . . . . . . . . . . . . . . in java.util.concurrent.FutureTask
| 1142 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 617 | run . . . . . . . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
Error |
Forked Grails VM exited with error
Any help or point in the right direction would be much appreciated
The bootsrap.groovy code was wrong
This following needs to be changed from
def user = new User(usernmae: 'user', password: 'user').save(flush: true, failOnError: true)
def admin = new User(usernmae: 'admin', password: 'admin').save(flush: true, failOnError: true)
Role(user: user, role: userRole).save(flush: true, failOnError: true)
new UserRole(user: admin, role: adminRole).save(flush: true, failOnError: true)
to
def user = new User(username: 'user', password: 'password', enabled: true).save()
def admin = new User(username: 'admin', password: 'password', enabled: true).save()
UserRole.create user, roleUser
UserRole.create admin, roleUser
UserRole.create admin, roleAdmin, true

how to code the Url for oracle database in grails dataSource.config

I'm trying to connect from grails to oracle 10gXE.
All over the net I only find a Url for localhost:
url = "jdbc:oracle:thin:#localhost:1521:XE"
But I need to connect to a host in my local network
I can ping it successfully with ping 192.168.2.128
but
url = "jdbc:oracle:thin:#192.168.2.128:1521:XE"
ends up with:
Error 2014-12-22 14:26:23,612 [localhost-startStop-1] ERROR pool.ConnectionPool - Unable to create initial connections of pool.
Message: E/A-Exception: The Network Adapter could not establish the connection
Line | Method
->> 112 | throwSqlException in oracle.jdbc.driver.DatabaseError
| 146 | throwSqlException in ''
| 255 | throwSqlException in ''
| 387 | logon in oracle.jdbc.driver.T4CConnection
| 414 | <init> . . . . . in oracle.jdbc.driver.PhysicalConnection
| 165 | <init> in oracle.jdbc.driver.T4CConnection
| 35 | getConnection . . in oracle.jdbc.driver.T4CDriverExtension
| 801 | connect in oracle.jdbc.driver.OracleDriver
| 262 | run . . . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
peter
Dortmund Germany
ps.
my complete Data source:
dataSource {
pooled = true
driverClassName = "oracle.jdbc.OracleDriver"
dialect = "org.hibernate.dialect.Oracle10gDialect"
username = "peter"
password = "wuffwuff"
}
environments {
development {
dataSource {
dbCreate = "update" // one of 'create', 'create-drop','update'
url = "jdbc:oracle:thin:#192.168.2.128:1521:XE"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:oracle:thin:#192.168.2.128:1521:XE"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:oracle:thin:#192.168.2.128:1521:XE"
username = "peter"
password = "wuffwuff"
}
}
}

Grails plugin returning invalid stream header error

I have a Grails app that uses a plugin I have created. Both use Spring-security-core plugin.
My plugin has a domain class, controller and views. Data to display is selected from a line drawn on a map. The data returned is displayed in a list at the bottom of the browser window. I have created a link on one of the fields that is supposed to show the selected record.
When I click this link, however I get the following error:
| Error 2014-05-27 16:14:11,415 [http-bio-8082-exec-6] ERROR errors.GrailsExceptionResolver - StreamCorruptedException occurred when processing request: [GET] /test/bridge/show/661
invalid stream header: 8401FE00. Stacktrace follows:
Message: invalid stream header: 8401FE00
Line | Method
->> 802 | readStreamHeader in java.io.ObjectInputStream
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 299 | <init> in ''
| 55 | show . . . . . . in RIMS.bridge.BridgeController
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . . . . in grails.plugin.cache.web.filter.AbstractFilter
| 53 | doFilter in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
| 49 | doFilter . . . . in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
| 82 | doFilter in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
| 1145 | runWorker . . . in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 724 | run . . . . . . in java.lang.Thread
The code that fails is where I attempt to get the data with the ID in the following action:
#Secured(["hasRole('ROLE_MAP_USER')"])
def show(Long id) {
println "ID: ${id}"
def princObj = springSecurityService?.principal
log.debug "User: ${princObj}"
def bridgeInstance = RIMS.bridge.Bridge.get(id)
if (!bridgeInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'bridge.label', default: 'Bridge'), id])
redirect(action: "list")
return
}
render(plugin: "nhvr", view:"show", model: [bridgeInstance: bridgeInstance])
}
The returned user, retured at log.debug "User: ${princObj}" is correct and has the required role.
I am not sure how to proceed. Can anyone suggest what to try?
Here is the code for the Bridge class:
package RIMS.bridge
class Bridge {
String bridgeNo
String roadNo
BigDecimal linkNo
BigDecimal chng
String travelDirectionCode
BigDecimal northing
BigDecimal easting
String overUnderCode
Date dateActive
Date dateArchived
String tranUser
Date tranDateTime
String tranType
Serializable obj
String cwayCode
String constructed
static hasMany = [
bridgeClearances: BridgeClearance,
bridgeCulverts: BridgeCulvert,
bridgeDimensions: BridgeDimension,
bridgeDrawings: BridgeDrawing,
bridgeDucts: BridgeDuct,
bridgeHydraulics: BridgeHydraulic,
bridgeMaintenances: BridgeMaintenance,
bridgeMiscellaneouses: BridgeMiscellaneous,
bridgeParts: BridgePart,
bridgeServices: BridgeService,
bridgeSpans: BridgeSpan,
bridgeSubstructures: BridgeSubstructure,
bridgeSuperstructures: BridgeSuperstructure]
static mapping = {
id generator: "assigned"
version false
}
static constraints = {
bridgeNo maxSize: 10
roadNo nullable: true, maxSize: 5
linkNo nullable: true
chng nullable: true
travelDirectionCode maxSize: 10
northing nullable: true
easting nullable: true
overUnderCode maxSize: 10
dateArchived nullable: true
tranUser maxSize: 30
tranType maxSize: 6
obj nullable: true
cwayCode nullable: true, maxSize: 4
constructed nullable: true, maxSize: 3
}
def locateByBridgeNo(String bridgeNo){
println "locating by no: ${bridgeNo}"
withCriteria{
eq('bridgeNo', bridgeNo)
}
}
static listActiveBridges(){
withCriteria(){
isNull('dateArchived')
}
}
static listBridgesByBridgeNo(String bridgeNo){
withCriteria(){
eq('bridgeNo', bridgeNo)
}
}
String toString(){
return "${bridgeNo} Road: ${roadNo}, Link: ${linkNo}, chainage: ${chng}"
}
}

ValidationException on Update: Validation error whilst flushing entity on AbstractPersistenceEventListener

In my environment, i have grails.gorm.failOnError = true on Config.groovy.
package org.example
class Book {
String title
String author
String email
static constraints = {
title nullable: false, blank: false
email nullable: false, blank: false, unique: true //apparently this is the problem..
}
}
And, on controller, i have:
package org.example
class BookController {
def update() {
def bookInstance = Book.get(params.id)
if (!bookInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])
redirect(action: "list")
return
}
if (params.version) {
def version = params.version.toLong()
if (bookInstance.version > version) {
bookInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[message(code: 'book.label', default: 'Book')] as Object[],
"Another user has updated this Book while you were editing")
render(view: "edit", model: [bookInstance: bookInstance])
return
}
}
bookInstance.properties = params
bookInstance.validate()
if(bookInstance.hasErrors()) {
render(view: "edit", model: [bookInstance: bookInstance])
} else {
bookInstance.save(flush: true)
flash.message = message(code: 'default.updated.message', args: [message(code: 'book.label', default: 'Book'), bookInstance.id])
redirect(action: "show", id: bookInstance.id)
}
}
}
To save, it's ok. But, when updating without set the title field, i get:
Message: Validation error whilst flushing entity [org.example.Book]:
- Field error in object 'org.example.Book' on field 'title': rejected value []; codes [org.example.Book.title.blank.error.org.example.Book.title,org.example.Book.title.blank.error.title,org.example.Book.title.blank.error.java.lang.String,org.example.Book.title.blank.error,book.title.blank.error.org.example.Book.title,book.title.blank.error.title,book.title.blank.error.java.lang.String,book.title.blank.error,org.example.Book.title.blank.org.example.Book.title,org.example.Book.title.blank.title,org.example.Book.title.blank.java.lang.String,org.example.Book.title.blank,book.title.blank.org.example.Book.title,book.title.blank.title,book.title.blank.java.lang.String,book.title.blank,blank.org.example.Book.title,blank.title,blank.java.lang.String,blank]; arguments [title,class org.example.Book]; default message [Property [{0}] of class [{1}] cannot be blank]
Line | Method
->> 46 | onApplicationEvent in org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 895 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 918 | run . . . . . . . in ''
^ 680 | run in java.lang.Thread
At q I understand it, the problem occurs when the flush hibernate session, hibernate tries to save the object again then the exception is thrown...
When trying to save the object again, is called the book.validate () again, which makes a new query in the database to ensure the uniqueness of the email field. Right now, the Validation Exception is thrown.
But, when i removed the unique validation of email property, the update is performed normally..
My question is: This behavior is correct? Hibernate calls book.save automatically?
This is the sample project, and the steps to simulate the error are:
source: https://github.com/roalcantara/grails_app_validation_exception
grails run-app
navigate to http:// localhost: 8080/ book/book/create
create an new instance filling all fields..
then edit this instance, in: http:// localhost: 8080/ book/book/edit/1
finally, drop the 'Title' field and click on Update, then the exception is thrown..
In my environment, this behavior has occurred on grails version 2.0.3 and 2.2.1
Thanks for any help! And sorry by my poor (and shame) english.. rs..
You are essentially validating twice, first with:
bookInstance.validate()
and second with:
bookInstance.save(flush: true)
When you call bookInstance.save(flush: true) a boolean is returned. Grails takes advantage of this by default when a controller is generated, but it appears you have changed the controller Grails generated by default for some reason.
Just replace this:
bookInstance.validate()
if(bookInstance.hasErrors()) {
render(view: "edit", model: [bookInstance: bookInstance])
} else {
bookInstance.save(flush: true)
flash.message = message(code: 'default.updated.message', args: [message(code: 'book.label', default: 'Book'), bookInstance.id])
redirect(action: "show", id: bookInstance.id)
}
With this:
if( !bookInstance.save( flush: true ) ) {
render(view: "edit", model: [bookInstance: bookInstance])
return
}

Grails + hibernate + controller sessionFactory null object?

I am new to using hibernate and grails. I have multiple java objects that I need to persist. To learn how it works I'm using a simple example of an employee class. Its in my src/java with the corresponding xml mappings with it. I think I need to make a session instance from my session factory, and I do not know what I'm doing wrong. I followed a tutorial for setting up hibternate hibernate tut and tried to translate it for grails. Any thoughts?
package com.turingpages.Matrix.view
import org.springframework.dao.DataIntegrityViolationException
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
class MatrixController {
def ctx = AH.application.mainContext
def sessionFactory = ctx.sessionFactory
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
...
def create() {
def session = sessionFactory.currentSession
Transaction tx = null;
Integer employeeID = null;
try{
tx = session.beginTransaction();
Employee employee = new Employee("fname", "lname", 100);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
My stack trace:
ERROR errors.GrailsExceptionResolver - NullPointerException occurred when processing request: [POST] /turingpages/matrix/create
Cannot get property 'currentSession' on null object. Stacktrace follows:
Message: Cannot get property 'currentSession' on null object
Line | Method
->> 33 | create in com.turingpages.Matrix.view.MatrixController$$ENvP7skK
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1110 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 603 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run in java.lang.Thread
There's no reason you should be writing code like that with Grails. If you really need to manage the transaction in a controller, you should do it this way.
def create() {
Integer employeeID = null;
Employee.withTransaction { status ->
Employee employee = new Employee(firstName: "fname", lastName: "lname", noIdea: 100);
employee.save()
if (employee.hasErrors()) {
status.setRollbackOnly()
}
}
return employee.id;
}
That said, when dealing with a single Domain like this, you don't really need to worry about it at all:
def create() {
Employee employee = new Employee(firstName: "fname", lastName: "lname", noIdea: 100);
employee.save(flush: true)
[employee: employee] // generally you want to pass the object back to a view this way
// deal with errors in the domain on the view
}
And even better would be to use a Service class. But that can be your homework assignment.
You need to move the code
def ctx = AH.application.mainContext
def sessionFactory = ctx.sessionFactory
into the method create(), or replace it with
def sessionFactory
However, Grails provides a withTransaction method to serve your purpose in a simpler way:
def create() {
Employee.withTransaction{ status ->
Employee employee = new Employee("fname", "lname", 100).save()
.....
if (employee.id) {
return employee.id
}
else {
status.setRollbackOnly()
}
}
}

Resources