Christian
Christian

Reputation: 914

Grails, custom validator, Hibernate assertion error

I'm trying to use a service in my domain class for custom validation. In other domain classes this works out pretty well but here I'm receiving a Hibernate assertion error.

domain class custom validation:

end validator: { val, obj ->

    if (obj.userWorkingTimeRegulationService.validateit() == false){
        return ["error.workingregulation"]
    }

I injected the service using:

def userWorkingTimeRegulationService

The service just returns true for testing purposes:

package usermanagement

import grails.transaction.Transactional

@Transactional
class UserWorkingTimeRegulationService {

    def serviceMethod() {

    }

    def validateit(){
        return true
    }
}

Stacktrace:

| Error 2015-05-27 15:07:54,909 [localhost-startStop-1] ERROR hibernate.AssertionFailure  - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in usermanagement.UserWorkingTimeRegulation entry (don't flush the Session after an exception occurs)
| Error 2015-05-27 15:07:54,927 [localhost-startStop-1] ERROR context.GrailsContextLoaderListener  - Error initializing the application: null id in usermanagement.UserWorkingTimeRegulation entry (don't flush the Session after an exception occurs)
Message: null id in usermanagement.UserWorkingTimeRegulation entry (don't flush the Session after an exception occurs)
    Line | Method
->>   24 | doCall                           in usermanagement.UserWorkingTimeRegulation$__clinit__closure4$_closure8
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     47 | onApplicationEvent               in org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
|     52 | create . . . . . . . . . . . . . in usermanagement.UserWorkingTimeRegulation
|     47 | 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

If I use a method declared in the domain class all works, there must be a problem with the service. In another domain class I used services without problems in my custom validation, I don't know what's so special about this one.

EDIT:

I create a UserWorkingTimeRegulation in my Bootstrap.groovy which is saved correctly if I comment the custom validation in my domain class which shouldn't do anything since the service is returning true and the validation kicks in with false.

Bootstrap:

UserWorkingTimeRegulation.create adminUser, workingTimeRegulation, new LocalDate(), new LocalDate().plusMonths(1)

Upvotes: 0

Views: 406

Answers (1)

Burt Beckwith
Burt Beckwith

Reputation: 75681

Services are transactional by default - the only way to make a service non-transactional is to add static transactional = false and remove all @Transactional annotations. The Spring/Hibernate transaction manager always flushes the Hibernate session at the end of a successful transaction, so what you're seeing is that after calling the service method (even one like yours which does no persistence), all modified persistent objects are flushed from the Hibernate cache to the database, but there's a problem with one of them.

The error message is fairly cryptic, but it's saying that a usermanagement.UserWorkingTimeRegulation doesn't have an id. This implies that you called save() but it didn't validate, so you need to check what values are missing or invalid by calling hasErrors and/or getErrors. The reason that not having an id is a problem is that this instance is a property of another domain object, and the id is used as the foreign key to link them together.

p.s. feel free to delete the unused autogenerated serviceMethod method.

Upvotes: 1

Related Questions