Problème de désérialisation de la session hibernate avec SWF
Salut à tous,
J'utilise SWF 2.4.1 et Hib 4.3.6 dans mon application.
La session hibernate étant liée à la session HTTP, celle-ci est sérialisée/désérialisée à chaque requête.
Dans mon flow à un moment, j'ai trois nouvelles entités avec A qui référence B et B qui référence C.
Ces objets sont mis dans la map entitySnapshotsByKey de la classe org.hibernate.engine.internal.StatefulPersistenceContext avec la valeur org.hibernate.engine.spi.PersistenceContext.NO_ROW (de type ObjectMarker)
Si persist() est appelé pour une nouvelle entité, une vérification dans la cache est faite pour les entités associées via la méthode org.hibernate.engine.internal.StatefulPersistenceContext.getDatabaseSnapshot(Serializable, EntityPersister).
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public Object[] getDatabaseSnapshot(Serializable id, EntityPersister persister) throws HibernateException {
final EntityKey key = session.generateEntityKey( id, persister );
final Object cached = entitySnapshotsByKey.get( key );
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;
}
} |
Le premier passage dans cette méthode va mettre les nouveaux objets dans entitySnapshotsByKey avec la valeur NO_ROW.
Une sérialisation/désérialisation a ensuite lieu lors du passage à l'écran suivant du flow.
Lors du persist() de la nouvelle entité suivante un call à getDatabaseSnapshot est de nouveau effectué et cette fois-ci les nouvelles entités étant disponibles, cached aura la valeur NO_ROW.
Le problème est là, suite à la désérialisation ce n'est plus la même référence que le NO_ROW de PersistenceContext!
Donc la ligne suivant "return cached == NO_ROW ? null : (Object[]) cached;" va essayer de caster l'ObjectMarker en Object[].
Donnant l'erreur suivante :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
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) |
Ma question est donc la suivant, est-il possible d'empêcher la sérialisation de la session hibernate dans la config SWF?
Est-ce un problème dans l'implémentation de la méthode org.hibernate.engine.internal.StatefulPersistenceContext.deserialize(ObjectInputStream, SessionImplementor) line 1530 qui ne gère pas correctement les désérialisation des ObjectMarker ou est-ce la comparaison de référence qui est une erreur? (pas de equals() disponible dans ObjectMarker)
Merci pour votre aide.