org.hibernate.AssertionFailure: collection [jawbs.domain.jobseeker.JobSeeker.categories] was not processed by flush()

Hibernate JIRA | Ken Egervari | 7 years ago
  1. 0

    The interaction with a hibernate session and sessions created within a validator do not work together. For example, here is a test case: {code} @Test public void jobSeekersCanSaveAPreviousResumeWithTheSameName() { JobSeekerResume resume = ( JobSeekerResume ) resumeDao.find( 1 ); resume.setDescription( "new desc." ); resumeDao.save( resume ); flush(); jdbcMap = simpleJdbcTemplate.queryForMap( "select * from resume where resume_id = ?", resume.getId() ); assertEquals( resume.getDescription(), jdbcMap.get( "DESCRIPTION" ) ); } {code} the flush() method creates an exception: {code} ERROR AssertionFailure:45 - 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: collection [jawbs.domain.jobseeker.JobSeeker.categories] was not processed by flush() at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:228) at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:356) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028) at jawbs.DatabaseTests.flush(DatabaseTests.java:113) {code} Obviously hibernate core is saying this could be a bug, or it could be unsafe. Now, the reason this happens is because JobSeekerResume has a contraint that accesses the hibernate session. Now, I have many, many constraints that use this constraint and they work fine. This is the only test that is causing problems for me, and I don't have a clue why. Nonetheless, I'm going to give you a lot of code. Here is the constraint annotation on JobSeekerResume: {code} @QueryConstraint( hql = "select count(*) from JobSeekerResume where name = :name and id != :id and jobSeeker.id = :jobSeeker.id", message = "{jobSeekerResume.name.unique}", enabled = true ) {code} And here is the code for the validator implementation: {code} public class QueryConstraintValidator extends ValidatorSupport<QueryConstraint,DomainObject> { /* Fields */ private String hql; private boolean enabled; /* Services */ public void initialize( QueryConstraint queryConstraint ) { this.hql = queryConstraint.hql(); this.enabled = queryConstraint.enabled(); } public boolean isValid( DomainObject domainObject ) { return isValid( domainObject, null ); } @Override protected boolean preValidate() { return !enabled; } protected boolean testQuery( Session session, DomainObject domainObject ) { logger.debug( "Enabled - Validating constraint with: " ); logger.debug( hql ); Query query = session.createQuery( HqlParser.removePeriodsFromParameterNames( hql ) ); BeanWrapper beanWrapper = new BeanWrapperImpl( domainObject ); for( String parameterName : HqlParser.getParameterNames( hql ) ) { query.setParameter( HqlParser.removePeriodsFromParameterName( parameterName ), beanWrapper.getPropertyValue( parameterName ) ); } boolean result = (Long) query.uniqueResult() == 0; logger.debug( "isValid is returning: " + result ); return result; } ... } {code} The support constraint (the important one most likely) is as follows: {code} public abstract class ValidatorSupport<T extends Annotation,U> implements ConstraintValidator<T,U> { /* Fields */ protected static Logger logger = LoggerFactory.getLogger( QueryConstraintValidator.class ); /* Services */ public boolean isValid( U object, ConstraintValidatorContext constraintValidatorContext ) { if( preValidate() ) { return true; } SessionFactory sessionFactory = ( SessionFactory ) ApplicationContextProvider.getBean( "sessionFactory" ); if( sessionFactory != null ) { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); boolean result = testQuery( session, object ); tx.commit(); session.close(); return result; } return true; } protected boolean preValidate() { return false; } protected abstract boolean testQuery( Session session, U object ); } {code} Lastly, here is the mapping of the JobSeeker subclass: {code} <subclass name="jawbs.domain.jobseeker.JobSeeker" discriminator-value="ROLE_JOBSEEKER"> <property name="isPrivate" column="is_private" /> <bag name="categories" table="job_seeker_to_category" cascade="all-delete-orphan" inverse="true"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.Category" column="category_id"/> </bag> <bag name="watchedJobs" table="job_seeker_to_watched_job" cascade="all-delete-orphan" inverse="true"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.job.Job" column="watched_job_id"/> </bag> <bag name="applications" table="candidate" cascade="all-delete-orphan" inverse="true"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.candidate.Candidate" column="candidate_id"/> </bag> <bag name="blacklistedEmployers" table="job_seeker_to_blacklisted_employer"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.employer.Employer" column="blacklisted_employer_id"/> </bag> <bag name="resumes" table="resume" inverse="true" cascade="all-delete-orphan"> <key column="job_seeker_id"/> <one-to-many class="jawbs.domain.resume.Resume" /> </bag> </subclass> {code} And here is the mapping of the subclass of resume: {code} <subclass name="jawbs.domain.resume.JobSeekerResume" discriminator-value="JOBSEEKER"> <many-to-one name="jobSeeker" class="jawbs.domain.jobseeker.JobSeeker" column="job_seeker_id" /> </subclass> {code} If you need any more assistance, please let me know. This is a critical blocker to getting a test to pass, this is most likely 100% fine. Thanks

    Hibernate JIRA | 7 years ago | Ken Egervari
    org.hibernate.AssertionFailure: collection [jawbs.domain.jobseeker.JobSeeker.categories] was not processed by flush()
  2. 0

    The interaction with a hibernate session and sessions created within a validator do not work together. For example, here is a test case: {code} @Test public void jobSeekersCanSaveAPreviousResumeWithTheSameName() { JobSeekerResume resume = ( JobSeekerResume ) resumeDao.find( 1 ); resume.setDescription( "new desc." ); resumeDao.save( resume ); flush(); jdbcMap = simpleJdbcTemplate.queryForMap( "select * from resume where resume_id = ?", resume.getId() ); assertEquals( resume.getDescription(), jdbcMap.get( "DESCRIPTION" ) ); } {code} the flush() method creates an exception: {code} ERROR AssertionFailure:45 - 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: collection [jawbs.domain.jobseeker.JobSeeker.categories] was not processed by flush() at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:228) at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:356) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028) at jawbs.DatabaseTests.flush(DatabaseTests.java:113) {code} Obviously hibernate core is saying this could be a bug, or it could be unsafe. Now, the reason this happens is because JobSeekerResume has a contraint that accesses the hibernate session. Now, I have many, many constraints that use this constraint and they work fine. This is the only test that is causing problems for me, and I don't have a clue why. Nonetheless, I'm going to give you a lot of code. Here is the constraint annotation on JobSeekerResume: {code} @QueryConstraint( hql = "select count(*) from JobSeekerResume where name = :name and id != :id and jobSeeker.id = :jobSeeker.id", message = "{jobSeekerResume.name.unique}", enabled = true ) {code} And here is the code for the validator implementation: {code} public class QueryConstraintValidator extends ValidatorSupport<QueryConstraint,DomainObject> { /* Fields */ private String hql; private boolean enabled; /* Services */ public void initialize( QueryConstraint queryConstraint ) { this.hql = queryConstraint.hql(); this.enabled = queryConstraint.enabled(); } public boolean isValid( DomainObject domainObject ) { return isValid( domainObject, null ); } @Override protected boolean preValidate() { return !enabled; } protected boolean testQuery( Session session, DomainObject domainObject ) { logger.debug( "Enabled - Validating constraint with: " ); logger.debug( hql ); Query query = session.createQuery( HqlParser.removePeriodsFromParameterNames( hql ) ); BeanWrapper beanWrapper = new BeanWrapperImpl( domainObject ); for( String parameterName : HqlParser.getParameterNames( hql ) ) { query.setParameter( HqlParser.removePeriodsFromParameterName( parameterName ), beanWrapper.getPropertyValue( parameterName ) ); } boolean result = (Long) query.uniqueResult() == 0; logger.debug( "isValid is returning: " + result ); return result; } ... } {code} The support constraint (the important one most likely) is as follows: {code} public abstract class ValidatorSupport<T extends Annotation,U> implements ConstraintValidator<T,U> { /* Fields */ protected static Logger logger = LoggerFactory.getLogger( QueryConstraintValidator.class ); /* Services */ public boolean isValid( U object, ConstraintValidatorContext constraintValidatorContext ) { if( preValidate() ) { return true; } SessionFactory sessionFactory = ( SessionFactory ) ApplicationContextProvider.getBean( "sessionFactory" ); if( sessionFactory != null ) { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); boolean result = testQuery( session, object ); tx.commit(); session.close(); return result; } return true; } protected boolean preValidate() { return false; } protected abstract boolean testQuery( Session session, U object ); } {code} Lastly, here is the mapping of the JobSeeker subclass: {code} <subclass name="jawbs.domain.jobseeker.JobSeeker" discriminator-value="ROLE_JOBSEEKER"> <property name="isPrivate" column="is_private" /> <bag name="categories" table="job_seeker_to_category" cascade="all-delete-orphan" inverse="true"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.Category" column="category_id"/> </bag> <bag name="watchedJobs" table="job_seeker_to_watched_job" cascade="all-delete-orphan" inverse="true"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.job.Job" column="watched_job_id"/> </bag> <bag name="applications" table="candidate" cascade="all-delete-orphan" inverse="true"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.candidate.Candidate" column="candidate_id"/> </bag> <bag name="blacklistedEmployers" table="job_seeker_to_blacklisted_employer"> <key column="job_seeker_id"/> <many-to-many class="jawbs.domain.employer.Employer" column="blacklisted_employer_id"/> </bag> <bag name="resumes" table="resume" inverse="true" cascade="all-delete-orphan"> <key column="job_seeker_id"/> <one-to-many class="jawbs.domain.resume.Resume" /> </bag> </subclass> {code} And here is the mapping of the subclass of resume: {code} <subclass name="jawbs.domain.resume.JobSeekerResume" discriminator-value="JOBSEEKER"> <many-to-one name="jobSeeker" class="jawbs.domain.jobseeker.JobSeeker" column="job_seeker_id" /> </subclass> {code} If you need any more assistance, please let me know. This is a critical blocker to getting a test to pass, this is most likely 100% fine. Thanks

    Hibernate JIRA | 7 years ago | Ken Egervari
    org.hibernate.AssertionFailure: collection [jawbs.domain.jobseeker.JobSeeker.categories] was not processed by flush()
  3. 0

    I'm getting a weird error that only occurs when the bean validation event listener is being activated. If I remove the constraint annotation, I don't have a problem - the test passes. This is the exception I get: ERROR AssertionFailure:45 - 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: collection [jawbs.domain.jobseeker.JobSeeker.watchedJobs] was not processed by flush() at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:228) at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:356) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028) at jawbs.DatabaseTests.flush(DatabaseTests.java:89) Here is the code that causes the exception - at the call to sessionFactory.getCurrentSession().flush() (which just happens to be flush() in this test method). @Test public void jobSeekersCanSaveAPreviousResumeWithTheSameName() { JobSeekerResume resume = ( JobSeekerResume ) resumeDao.find( 1 ); resume.setDescription( "new desc." ); resumeDao.save( resume ); flush(); jdbcMap = simpleJdbcTemplate.queryForMap( "select * from resume where resume_id = ?", resume.getId() ); assertEquals( resume.getDescription(), jdbcMap.get( "DESCRIPTION" ) ); } I don't think the mappings are really that important. Basically, "JobSeekerResume" contains a "JobSeeker", and JobSeeker contains many collections. Every time I run the test, I randomly get this error for any of the collections within the JobSeeker object. In the exception above, it just happened to be the "watchedJobs" collection property. It changes every time I run the test. Now, the reason this problem is happening is that my constraint also hits the database. The constraint asks the sessionFactory to open a session, start a transaction, execute a query, close the transaction and then finally close the session. I've also tried it with a StatelessSession instead, but the same problem persists. Here is the query: select count(*) from JobSeekerResume where name = :name and id != :id and jobSeeker.id = :jobSeekerId Here is the constraint code: public boolean isValid( DomainObject domainObject, ConstraintValidatorContext context ) { BeanWrapper beanWrapper = new BeanWrapperImpl( domainObject ); SessionFactory sessionFactory = ( SessionFactory ) ApplicationContextProvider.getBean( "sessionFactory" ); if( enabled && sessionFactory != null ) { logger.debug( "Enabled - Validating constraint with: " ); logger.debug( hql ); StatelessSession session = sessionFactory.openStatelessSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery( HqlParser.removePeriodsFromParameterNames( hql ) ); for( String parameterName : HqlParser.getParameterNames( hql ) ) { query.setParameter( HqlParser.removePeriodsFromParameterName( parameterName ), beanWrapper.getPropertyValue( parameterName ) ); } boolean result = (Long) query.uniqueResult() == 0; logger.debug( "isValid is returning: " + result ); tx.commit(); session.close(); return result; } return true; } Now, this query is 100% fine in isolation... and by using logging information, everything is working - the query, the sessions are getting closed, etc. as well. It is curious though that if I disable this constraint, the test passes. With this constraint... it does not. Is this a problem with my constraint? With the bean validation event listener? I'd appreciate any help... and if it is a bug, that it gets fixed. Thank you.

    Hibernate JIRA | 7 years ago | Ken Egervari
    org.hibernate.AssertionFailure: collection [jawbs.domain.jobseeker.JobSeeker.watchedJobs] was not processed by flush()
  4. Speed up your debug routine!

    Automated exception search integrated into your IDE

  5. 0

    I'm getting a weird error that only occurs when the bean validation event listener is being activated. If I remove the constraint annotation, I don't have a problem - the test passes. This is the exception I get: ERROR AssertionFailure:45 - 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: collection [jawbs.domain.jobseeker.JobSeeker.watchedJobs] was not processed by flush() at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:228) at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:356) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028) at jawbs.DatabaseTests.flush(DatabaseTests.java:89) Here is the code that causes the exception - at the call to sessionFactory.getCurrentSession().flush() (which just happens to be flush() in this test method). @Test public void jobSeekersCanSaveAPreviousResumeWithTheSameName() { JobSeekerResume resume = ( JobSeekerResume ) resumeDao.find( 1 ); resume.setDescription( "new desc." ); resumeDao.save( resume ); flush(); jdbcMap = simpleJdbcTemplate.queryForMap( "select * from resume where resume_id = ?", resume.getId() ); assertEquals( resume.getDescription(), jdbcMap.get( "DESCRIPTION" ) ); } I don't think the mappings are really that important. Basically, "JobSeekerResume" contains a "JobSeeker", and JobSeeker contains many collections. Every time I run the test, I randomly get this error for any of the collections within the JobSeeker object. In the exception above, it just happened to be the "watchedJobs" collection property. It changes every time I run the test. Now, the reason this problem is happening is that my constraint also hits the database. The constraint asks the sessionFactory to open a session, start a transaction, execute a query, close the transaction and then finally close the session. I've also tried it with a StatelessSession instead, but the same problem persists. Here is the query: select count(*) from JobSeekerResume where name = :name and id != :id and jobSeeker.id = :jobSeekerId Here is the constraint code: public boolean isValid( DomainObject domainObject, ConstraintValidatorContext context ) { BeanWrapper beanWrapper = new BeanWrapperImpl( domainObject ); SessionFactory sessionFactory = ( SessionFactory ) ApplicationContextProvider.getBean( "sessionFactory" ); if( enabled && sessionFactory != null ) { logger.debug( "Enabled - Validating constraint with: " ); logger.debug( hql ); StatelessSession session = sessionFactory.openStatelessSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery( HqlParser.removePeriodsFromParameterNames( hql ) ); for( String parameterName : HqlParser.getParameterNames( hql ) ) { query.setParameter( HqlParser.removePeriodsFromParameterName( parameterName ), beanWrapper.getPropertyValue( parameterName ) ); } boolean result = (Long) query.uniqueResult() == 0; logger.debug( "isValid is returning: " + result ); tx.commit(); session.close(); return result; } return true; } Now, this query is 100% fine in isolation... and by using logging information, everything is working - the query, the sessions are getting closed, etc. as well. It is curious though that if I disable this constraint, the test passes. With this constraint... it does not. Is this a problem with my constraint? With the bean validation event listener? I'd appreciate any help... and if it is a bug, that it gets fixed. Thank you.

    Hibernate JIRA | 7 years ago | Ken Egervari
    org.hibernate.AssertionFailure: collection [jawbs.domain.jobseeker.JobSeeker.watchedJobs] was not processed by flush()
  6. 0

    [1.3.0] When did you plan to release it

    Google Groups | 4 years ago | Alex
    org.hibernate.AssertionFailure: collection [models.User.tags] was not processed by flush()

  1. musketyr 4 times, last 4 weeks ago
Not finding the right solution?
Take a tour to get the most out of Samebug.

Tired of useless tips?

Automated exception search integrated into your IDE

Root Cause Analysis

  1. org.hibernate.AssertionFailure

    collection [jawbs.domain.jobseeker.JobSeeker.categories] was not processed by flush()

    at org.hibernate.engine.CollectionEntry.postFlush()
  2. Hibernate
    CollectionEntry.postFlush
    1. org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:228)
    1 frame
  3. Hibernate
    SessionImpl.flush
    1. org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:356)
    2. org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    3. org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)
    3 frames
  4. jawbs
    DatabaseTests.flush
    1. jawbs.DatabaseTests.flush(DatabaseTests.java:113)
    1 frame