I have a problem with hibernate 4.3.6 and spring webflow 2.4.1.
I don't use a store for the flows so the persistence context is linked to the HTTP session and when changing page in the flow it calls a deserialization/serialization of the hibernate session.
At a moment in the flow, i have 3 new entities (referencing each other), those are stored in the entitySnapshotsByKey map of the
org.hibernate.engine.internal.StatefulPersistenceContext with the static final property
NO_ROW as value (from
org.hibernate.engine.spi.PersistenceContext).
When going to the next page deserialization/serialization of the hibernate session is done. The next call to persist() will check if the new entity already exists in the cache using the method :
org.hibernate.engine.internal.StatefulPersistenceContext.getDatabaseSnapshot(Serializable, EntityPersister).
The problem is, ithe following piece of code of this method :
Code:
if ( cached != null ) {
return cached == NO_ROW ? null : (Object[]) cached;
}
else {
final Object[] snapshot = persister.getDatabaseSnapshot( id, session );
entitySnapshotsByKey.put( key, snapshot == null ? NO_ROW : snapshot );
return snapshot;
}
The cached values are in the map (they are deserialized at this moment) so the following line is executed :
Code:
return cached == NO_ROW ? null : (Object[]) cached;
"cached" has indeed the value NO_ROW but not the same reference than the static final field of PersistenceContext because it was deserialized so "cached == NO_ROW" will never be true and the MarkerObject will be casted to Object[]!My opinion is that the method
public static StatefulPersistenceContext deserialize(ObjectInputStream ois, SessionImplementor session) is incomplete.
It causes the following ClassCastException :
Code:
java.lang.ClassCastException: org.hibernate.internal.util.MarkerObject cannot be cast to [Ljava.lang.Object;
at org.hibernate.engine.internal.StatefulPersistenceContext.getDatabaseSnapshot(StatefulPersistenceContext.java:313)
at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:255)
at org.hibernate.engine.internal.ForeignKeys$Nullifier.isNullifiable(ForeignKeys.java:177)
at org.hibernate.engine.internal.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:105)
at org.hibernate.engine.internal.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:81)
at org.hibernate.action.internal.AbstractEntityInsertAction.nullifyTransientReferencesIfNotAlready(AbstractEntityInsertAction.java:130)
at org.hibernate.action.internal.AbstractEntityInsertAction.makeEntityManaged(AbstractEntityInsertAction.java:141)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:201)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:179)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:166)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:332)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at core.dao.generic.AbstractHibernateDao.persist(AbstractHibernateDao.java:45)
at web.flow.controller.DenoFlowController.saveDenomination(DenoFlowController.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:63)
at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:95)
at org.springframework.expression.spel.ast.MethodReference.access$000(MethodReference.java:44)
at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:258)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:84)
at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:114)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:105)
at org.springframework.binding.expression.spel.SpringELExpression.getValue(SpringELExpression.java:84)
at org.springframework.webflow.action.EvaluateAction.doExecute(EvaluateAction.java:75)
at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188)
at org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145)
at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51)
at org.springframework.webflow.engine.support.ActionTransitionCriteria.test(ActionTransitionCriteria.java:82)
at org.springframework.webflow.engine.support.TransitionCriteriaChain.test(TransitionCriteriaChain.java:68)
at org.springframework.webflow.engine.Transition.canExecute(Transition.java:196)
at org.springframework.webflow.engine.Transition.execute(Transition.java:212)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.execute(FlowExecutionImpl.java:395)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.execute(RequestControlContextImpl.java:214)
at org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:116)
at org.springframework.webflow.engine.Flow.handleEvent(Flow.java:547)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:390)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210)
at org.springframework.webflow.engine.ViewState.handleEvent(ViewState.java:231)
at org.springframework.webflow.engine.ViewState.resume(ViewState.java:195)
at org.springframework.webflow.engine.Flow.resume(Flow.java:537)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
It seems to be a bug but i can't believe that i'm the first one encountering this issue because apparently this piece of code hasn't changed in years.
Did someone already have a similar problem?
I clearly don't see what i'm doing wrong as it's all hibernate internal business.
Thanks.
Edit : Created JIRA ticket https://hibernate.atlassian.net/browse/HHH-9414