Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPE in Hibernate's BatchFetchQueue.removeBatchLoadableEntityKey(...) #10096

Closed
babanin opened this issue Aug 11, 2016 · 2 comments
Closed

NPE in Hibernate's BatchFetchQueue.removeBatchLoadableEntityKey(...) #10096

babanin opened this issue Aug 11, 2016 · 2 comments

Comments

@babanin
Copy link

babanin commented Aug 11, 2016

Hello, guys! I have a problem with dependent entity persist.

I have two primitive entities:

User

class User {
    String loginId
    String password

    static hasOne = [person: Person]

    static constraints = {
    }
}

Person

class Person {
    User user
    String name
    String surname

    static constraints = {
    }
}

and simple integration test:

@Integration
@Rollback
class UserIntegrationSpec extends Specification {
    void "user save fails with exception"() {
        given: "A brand new user"
        def user = new User(loginId: "joe", password: "secret", person: new Person(name: "Gary"))

        when: "the user is saved"
        user.save(failsOnError: true)

        then: "it saved successfully and can be found in the database"
        user.errors.errorCount == 0
    }
}

When I run this test from console (grails test-app) I got following exception from deep Hibernate internals:

java.lang.NullPointerException
    at org.hibernate.engine.spi.BatchFetchQueue.removeBatchLoadableEntityKey(BatchFetchQueue.java:163)
    at org.hibernate.engine.internal.StatefulPersistenceContext.addEntity(StatefulPersistenceContext.java:389)
    at org.hibernate.engine.internal.StatefulPersistenceContext.addEntity(StatefulPersistenceContext.java:462)
    at org.hibernate.action.internal.AbstractEntityInsertAction.makeEntityManaged(AbstractEntityInsertAction.java:143)
    at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:203)
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:181)
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:216)
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:334)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:289)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:195)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:126)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
    at org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor.onSaveOrUpdate(ClosureEventTriggeringInterceptor.java:105)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676)
    at org.hibernate.engine.spi.CascadingActions$5.cascade(CascadingActions.java:235)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:470)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:295)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:195)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:126)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
    at org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor.onSaveOrUpdate(ClosureEventTriggeringInterceptor.java:105)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:671)
    at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.performSave_closure3(AbstractHibernateGormInstanceApi.groovy:235)
    at groovy.lang.Closure.call(Closure.java:414)
    at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:196)
    at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:140)
    at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:110)
    at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.performSave(AbstractHibernateGormInstanceApi.groovy:234)
    at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.save(AbstractHibernateGormInstanceApi.groovy:154)
    at org.grails.datastore.gorm.GormEntity$Trait$Helper.save(GormEntity.groovy:151)
    at dependent.entity.fail.validate.UserIntegrationSpec.$tt__$spock_feature_0_0(UserIntegrationSpec.groovy:15)
    at dependent.entity.fail.validate.UserIntegrationSpec.test user save_closure1(UserIntegrationSpec.groovy)
    at groovy.lang.Closure.call(Closure.java:414)
    at groovy.lang.Closure.call(Closure.java:430)
    at grails.transaction.GrailsTransactionTemplate$1.doInTransaction(GrailsTransactionTemplate.groovy:70)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
    at grails.transaction.GrailsTransactionTemplate.executeAndRollback(GrailsTransactionTemplate.groovy:67)
    at dependent.entity.fail.validate.UserIntegrationSpec.test user save(UserIntegrationSpec.groovy)

This is slightly changed example from Grails in action book (2ed).

What's wrong with it?

After digging for a while in Hibernate internals, all that I understand is that there is no entity key for Person :) And as I understand, it should be created during EntityIdentityInsertAction execution, but entityKey creation was vetoed by ClosureEventTriggeringInterceptor (which extends PreInsertEventListener).

BTW, test project can be found here: https://github.com/babanin/grails-dependent-entity-fail-validate

@babanin babanin changed the title NPE in o.h.engine.spi.BatchFetchQueue.removeBatchLoadableEntityKey(...) NPE in Hibernate's BatchFetchQueue.removeBatchLoadableEntityKey(...) Aug 11, 2016
@jameskleeh
Copy link
Contributor

It's because the Person object failed validation. Duplicate of #9820

@ppazos
Copy link

ppazos commented Dec 25, 2022

If the Person fails validation, it should return a validation error because of the failsOnError: true, not a NPE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants