Reputation: 33
I have to make a Grails 3.3.0 web interface for my internship with PostgreSQL version 10.1 as database and spring-security-core version 3.2.0.
I've installed PostgreSQL on my Linux laptop and created the webInterfaceDev database with the user Postgres.
However, every time I want to start the project I get the error "object references an unsaved transient instance".
This is the error that I get:
2017-11-23 11:26:55.634 ERROR --- [ main] o.s.boot.SpringApplication : Application startup failed
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.domain.auth.User
at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:279)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:462)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:153)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:2051)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:2020)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1950)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1903)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1881)
at org.hibernate.loader.Loader.doQuery(Loader.java:925)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doList(Loader.java:2622)
at org.hibernate.loader.Loader.doList(Loader.java:2605)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2434)
at org.hibernate.loader.Loader.list(Loader.java:2429)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
at org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:716)
at org.grails.orm.hibernate.query.AbstractHibernateQuery.list(AbstractHibernateQuery.java:706)
at org.grails.datastore.gorm.finders.FindAllByFinder.invokeQuery(FindAllByFinder.java:54)
at org.grails.datastore.gorm.finders.FindAllByFinder$1.doInSession(FindAllByFinder.java:48)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:319)
at org.grails.datastore.gorm.finders.AbstractFinder.execute(AbstractFinder.java:42)
at org.grails.datastore.gorm.finders.FindAllByFinder.doInvokeInternal(FindAllByFinder.java:45)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:254)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:392)
at org.grails.datastore.gorm.finders.FinderMethod$invoke$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:141)
at org.grails.datastore.gorm.GormStaticApi.methodMissing(GormStaticApi.groovy:185)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.staticMethodMissing(GormEntity.groovy:756)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1446)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:899)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:168)
at com.domain.auth.UserRole.staticMethodMissing(UserRole.groovy)
at com.domain.auth.UserRole.$static_methodMissing(UserRole.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1499)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at com.domain.auth.User.getAuthorities(User.groovy:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.MethodMetaProperty$GetBeanMethodMetaProperty.getProperty(MethodMetaProperty.java:76)
at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:85)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
at web_interface.BootStrap$_closure1.doCall(BootStrap.groovy:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1087)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:408)
at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.java:535)
at grails.util.Environment.executeForEnvironment(Environment.java:528)
at grails.util.Environment.executeForCurrentEnvironment(Environment.java:504)
at org.grails.web.servlet.boostrap.DefaultGrailsBootstrapClass.callInit(DefaultGrailsBootstrapClass.java:74)
at org.grails.web.servlet.context.GrailsConfigUtils.executeGrailsBootstraps(GrailsConfigUtils.java:65)
at org.grails.plugins.web.servlet.context.BootStrapClassRunner.onStartup(BootStrapClassRunner.groovy:53)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:261)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
at grails.boot.GrailsApp.run(GrailsApp.groovy:387)
at grails.boot.GrailsApp.run(GrailsApp.groovy:374)
at grails.boot.GrailsApp$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at web_interface.Application.main(Application.groovy:8)
FAILURE: Build failed with an exception.
Below is the code that I used:
grails-app/conf/application.yml
---
grails:
profile: web
codegen:
defaultPackage: web_interface
spring:
transactionManagement:
proxies: false
gorm:
reactor:
# Whether to translate GORM events into Reactor events
# Disabled by default for performance reasons
events: false
info:
app:
name: '@info.app.name@'
version: '@info.app.version@'
grailsVersion: '@info.app.grailsVersion@'
spring:
main:
banner-mode: "off"
groovy:
template:
check-template-location: false
# Spring Actuator Endpoints are Disabled by Default
endpoints:
enabled: false
jmx:
enabled: true
---
grails:
mime:
disable:
accept:
header:
userAgents:
- Gecko
- WebKit
- Presto
- Trident
types:
all: '*/*'
atom: application/atom+xml
css: text/css
csv: text/csv
form: application/x-www-form-urlencoded
html:
- text/html
- application/xhtml+xml
js: text/javascript
json:
- application/json
- text/json
multipartForm: multipart/form-data
pdf: application/pdf
rss: application/rss+xml
text: text/plain
hal:
- application/hal+json
- application/hal+xml
xml:
- text/xml
- application/xml
urlmapping:
cache:
maxsize: 1000
controllers:
defaultScope: singleton
converters:
encoding: UTF-8
views:
default:
codec: html
gsp:
encoding: UTF-8
htmlcodec: xml
codecs:
expression: html
scriptlets: html
taglib: none
staticparts: none
endpoints:
jmx:
unique-names: true
---
hibernate:
cache:
queries: false
use_second_level_cache: false
use_query_cache: false
dataSource:
pooled: true
jmxExport: true
#mem database driver and password
#driverClassName: org.h2.Driver
#username: sa
#password:
#PostgreSQL driver and password
driverClassName: org.postgresql.Driver
username: postgres
password: password
environments:
development:
dataSource:
dbCreate: update #use create-drop or update
#Use for mem database
#url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
#Use for PostgreSQL database
url: jdbc:postgresql://localhost:5432/webInterfaceDev
test:
dataSource:
dbCreate: update
url: jdbc:postgresql:webInterfaceDev
production:
dataSource:
dbCreate: update
url: jdbc:postgresql:webInterfaceDev
properties:
jmxEnabled: true
initialSize: 5
maxActive: 50
minIdle: 5
maxIdle: 25
maxWait: 10000
maxAge: 600000
timeBetweenEvictionRunsMillis: 5000
minEvictableIdleTimeMillis: 60000
validationQuery: SELECT 1
validationQueryTimeout: 3
validationInterval: 15000
testOnBorrow: true
testWhileIdle: true
testOnReturn: false
jdbcInterceptors: ConnectionState
defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
Below is the build.gradle code:
buildscript {
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
}
dependencies {
classpath "org.grails:grails-gradle-plugin:$grailsVersion"
classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}"
classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.14.2"
}
}
version "0.1"
group "web_interface"
apply plugin:"eclipse"
apply plugin:"idea"
apply plugin:"war"
apply plugin:"org.grails.grails-web"
apply plugin:"asset-pipeline"
apply plugin:"org.grails.grails-gsp"
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
}
dependencies {
//plugins needed to make the user system
compile 'org.grails.plugins:spring-security-core:3.2.0'
compile 'org.grails.plugins:spring-security-ui:3.1.1'
//end of the plugins needed
//postgresql
compile 'org.postgresql:postgresql:42.1.4.jre7'
//end
compile "org.springframework.boot:spring-boot-starter-logging"
compile "org.springframework.boot:spring-boot-autoconfigure"
compile "org.grails:grails-core"
compile "org.springframework.boot:spring-boot-starter-actuator"
compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.grails:grails-web-boot"
compile "org.grails:grails-logging"
compile "org.grails:grails-plugin-rest"
compile "org.grails:grails-plugin-databinding"
compile "org.grails:grails-plugin-i18n"
compile "org.grails:grails-plugin-services"
compile "org.grails:grails-plugin-url-mappings"
compile "org.grails:grails-plugin-interceptors"
compile "org.grails.plugins:cache"
compile "org.grails.plugins:async"
compile "org.grails.plugins:scaffolding"
compile "org.grails.plugins:events"
compile "org.grails.plugins:hibernate5"
compile "org.hibernate:hibernate-core:5.1.5.Final"
compile "org.grails.plugins:gsp"
console "org.grails:grails-console"
profile "org.grails.profiles:web"
runtime "org.glassfish.web:el-impl:2.1.2-b03"
runtime "com.h2database:h2"
runtime "org.apache.tomcat:tomcat-jdbc"
runtime "com.bertramlabs.plugins:asset-pipeline-grails:2.14.2"
testCompile "org.grails:grails-gorm-testing-support"
testCompile "org.grails.plugins:geb"
testCompile "org.grails:grails-web-testing-support"
testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
}
bootRun {
jvmArgs('-Dspring.output.ansi.enabled=always')
addResources = true
}
assets {
minifyJs = true
minifyCss = true
}
Below is the User.groovy code:
package com.domain.auth
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
@EqualsAndHashCode(includes='username')
@ToString(includes='username', includeNames=true, includePackage=false)
class User implements Serializable {
private static final long serialVersionUID = 1
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Set<Role> getAuthorities() {
(UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
}
static constraints = {
password nullable: false, blank: false, password: true
username nullable: false, blank: false, unique: true
}
static mapping = {
table '`User`' //user is properity for postgresql insted i use now User as table name
password column: '`password`'
}
}
Bootstrap.groovy code:
package web_interface
import com.domain.auth.*
//class BootStrap {
// def passwordEncoder
//
// def init = { servletContext ->
// def adminRole = Role.findOrSaveWhere(authority:"ROLE_ADMIN")
// def user = User.findOrSaveWhere(username:"admin", password: "password").save(flush: true)
// if(!user.authorities.contains(adminRole)){
// UserRole.create(user,adminRole,true)
// }
// }
// def destroy = {
// }
//}
class BootStrap{
def init = { servletContext ->
if(User.count() == 0){
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush:true)
def admin = new User(username: 'admin', password: 'password').save(flush:true)
UserRole.create admin, adminRole
// as we call to create, flush the session explicitly ..
UserRole.withSession {
it.flush()
it.clear()
}
// instead you can put >
// new UserRole(admin, adminRole).save(flush:true)
// Do more stuff with admin user
}
}
def destroy = {
}
}
UserRole.groovy code:
package com.domain.auth
import grails.gorm.DetachedCriteria
import groovy.transform.ToString
import org.codehaus.groovy.util.HashCodeHelper
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
@ToString(cache=true, includeNames=true, includePackage=false)
class UserRole implements Serializable {
private static final long serialVersionUID = 1
User user
Role role
@Override
boolean equals(other) {
if (other instanceof UserRole) {
other.userId == user?.id && other.roleId == role?.id
}
}
@Override
int hashCode() {
int hashCode = HashCodeHelper.initHash()
if (user) {
hashCode = HashCodeHelper.updateHash(hashCode, user.id)
}
if (role) {
hashCode = HashCodeHelper.updateHash(hashCode, role.id)
}
hashCode
}
static UserRole get(long userId, long roleId) {
criteriaFor(userId, roleId).get()
}
static boolean exists(long userId, long roleId) {
criteriaFor(userId, roleId).count()
}
private static DetachedCriteria criteriaFor(long userId, long roleId) {
UserRole.where {
user == User.load(userId) &&
role == Role.load(roleId)
}
}
static UserRole create(User user, Role role, boolean flush = false) {
def instance = new UserRole(user: user, role: role)
instance.save(flush: flush)
instance
}
static boolean remove(User u, Role r) {
if (u != null && r != null) {
UserRole.where { user == u && role == r }.deleteAll()
}
}
static int removeAll(User u) {
u == null ? 0 : UserRole.where { user == u }.deleteAll() as int
}
static int removeAll(Role r) {
r == null ? 0 : UserRole.where { role == r }.deleteAll() as int
}
static constraints = {
user nullable: false, unique: true
role nullable: false, validator: { Role r, UserRole ur ->
if (ur.user?.id) {
if (UserRole.exists(ur.user.id, r.id)) {
return ['userRole.exists']
}
}
user.save()
}
}
static mapping = {
id composite: ['user', 'role']
version false
}
}
Role.groovy code:
package com.domain.auth
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
@EqualsAndHashCode(includes='authority')
@ToString(includes='authority', includeNames=true, includePackage=false)
class Role implements Serializable {
private static final long serialVersionUID = 1
String authority
static constraints = {
authority nullable: false, blank: false, unique: true
}
static mapping = {
cache true
}
}
Upvotes: 0
Views: 846
Reputation: 431
In your Bootstrap.groovy
, try simple thing as below
def init = { servletContext ->
if(User.count() == 0){
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush:true)
def admin = new User(username: 'admin', password: 'testpassed').save(flush:true)
UserRole.create admin, adminRole
// as we call to create, flush the session explicitly ..
UserRole.withSession {
it.flush()
it.clear()
}
// instead you can put >
// new UserRole(admin, adminRole).save(flush:true)
// Do more stuff with admin user
}
}
Just a small thing, put your db url
in your application.yml
url: jdbc:postgresql://localhost:5432/yourDBName
Upvotes: 0
Reputation: 431
Long story in short
Your User.findOrSaveWhere(username:"admin", password:"password")
is the problem. If you try without password:"password"
your code will run considering setting the password user.password='password'
while initiating new User
.
The saved password in the DB is hashed and it doesn't match with your given password. So, everytime you run the app, it doesn't find matching user and tries to save a new User with same username
violating the unique
constraints.
Deatils -
I tried with below codes -
def xadminRole = Role.findOrSaveWhere(authority:"XYZROLE_XADMIN")
def xuser = User.findOrSaveWhere(username:"xxzadmin", password:"password")
if(!xuser.authorities.contains(xadminRole)){
UserRole.create(xuser,xadminRole,true)
}
First time its working fine and inserting the User
2nd time I ran the app i got user instance has below errors
Field error in object 'com.xxx.ovr.User' on field 'username': rejected value [xxzadmin]; codes [[username,class com.xxx.ovr.User,xxzadmin]; default message [Property [{0}] of class [{1}] with value [{2}] must be unique]
and finally
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.xxx.ovr.User
The user's password-
$2a$10$b1Ybjt9.XVgkDi.HRgGgpeyL7WsSFMFl0jpSWy60JfTfTDNRQH/Fu
$2a$10$8HTYeE8uJgmMzclc0lku5euUpNfqa3RUZeBBs7XaJ9Z5CpT/0Prtq
So you can not find a user
with plain password - 'password' which is saved in DB after hashed (example given above). To match a user with username and password you can check the posts -
spring security encode password with bcrypt algorithm
Grails Spring-Security -how to compare passwords-
UPDATE
With @BurtBeckwith's useful comment, I corrected the answer putting "hashed" in place of "encrypted"
For Password Hash algorithm, please check 1.2 and 3.3.2 section of https://grails-plugins.github.io/grails-spring-security-core/latest/
Related post
Using BCrypt password hashing with Spring Security Grails plugin
For difference between Hash
and Encryption
please check
Difference between Hashing a Password and Encrypting it
Fundamental difference between Hashing and Encryption algorithms
Upvotes: 1