Versionning problem in case of autoFlush required inside an "onSave" interceptor

Description

I have an interceptor "onSave" for an Entity.
I try to make a query with hibernate inside this onSave.
The following exception is thrown :

java.lang.NullPointerException
at org.hibernate.type.IntegerType.next(IntegerType.java:82)
at org.hibernate.engine.Versioning.increment(Versioning.java:131)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getNextVersion(DefaultFlushEntityEventListener.java:406)
at org.hibernate.event.def.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:296)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:155)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1175)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1699)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)
at org.springframework.orm.hibernate3.HibernateTemplate$36.doInHibernate(HibernateTemplate.java:1056)
at org.springframework.orm.hibernate3.HibernateTemplate$36.doInHibernate(HibernateTemplate.java:1)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
...

As you can see, my query triggers an auto flush, because I try to read some objects related to the object currently saved (I cannot access these related objects another way, some relations are not bidirectionnal).
During this auto flush, I have a null pointer inside Versioning.increment because the EntityEntry has a null version, whereas my entity has a version.
I think that the version inside my own entity is not already reported inside the EntityEntry - the proof is in the stack trace before the onSave call:

...
at org.hibernate.event.def.AbstractSaveEventListener.substituteValuesIfNecessary(AbstractSaveEventListener.java:414)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:293)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
...

As you can see, AbstractSaveEventListener.substituteValuesIfNecessary calls my method. But this method also process versionning :

398 /**
399 * Perform any property value substitution that is necessary
400 * (interceptor callback, version initialization...)
401 *
402 * @param entity The entity
403 * @param id The entity identifier
404 * @param values The snapshot entity state
405 * @param persister The entity persister
406 * @param source The originating session
407 *
408 * @return True if the snapshot state changed such that
409 * reinjection of the values into the entity is required.
410 */
411 protected boolean substituteValuesIfNecessary(
412 Object entity,
413 Serializable id,
414 Object[] values,
415 EntityPersister persister,
416 SessionImplementor source) {
417 boolean substitute = source.getInterceptor().onSave(
418 entity,
419 id,
420 values,
421 persister.getPropertyNames(),
422 persister.getPropertyTypes()
423 );
424
425 //keep the existing version number in the case of replicate!
426 if ( persister.isVersioned() ) {
427 substitute = Versioning.seedVersion(
428 values,
429 persister.getVersionProperty(),
430 persister.getVersionType(),
431 source
432 ) || substitute;
433 }
434 return substitute;
435 }

"Versioning.seedVersion" is called after "source.getInterceptor().onSave"

Maybe the version should have already been reported inside the EntityEntry when calling onSave ?

Environment

Hibernate 3.5.6, Oracle

Activity

Show:
Romain Fromi
November 7, 2011, 4:25 PM

During the research I made, I saw this entry : https://hibernate.onjira.com/browse/HHH-3030

And this post : https://forum.hibernate.org/viewtopic.php?f=1&t=995904

So I am not the first one falling into this pit !

Brett Meyer
April 7, 2014, 5:43 PM

In an effort to clean up, in bulk, tickets that are most likely out of date, we're transitioning all ORM 3 tickets to an "Awaiting Test Case" state. Please see http://in.relation.to/Bloggers/HibernateORMJIRAPoliciesAndCleanUpTactics for more information.

If this is still a legitimate bug in ORM 4, please provide either a test case that reproduces it or enough detail (entities, mappings, snippets, etc.) to show that it still fails on 4. If nothing is received within 3 months or so, we'll be automatically closing them.

Thank you!

Brett Meyer
July 8, 2014, 3:11 PM

Bulk rejecting stale issues. If this is still a legitimate issue on ORM 4, feel free to comment and attach a test case. I'll address responses case-by-case. Thanks!

Assignee

Unassigned

Reporter

Romain Fromi

Fix versions

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

Priority

Major
Configure