When using Web Flow (2.3.1.RELEASE) in combination with JSF, I have a rendering problem when using a composite component of any kind and e.g. an <h:outputLabel /> component on 1 page after clicking a <h:commandLink />. The contents of the composite component are always displayed at the bottom of the page! When refreshing the page, rendering is fine again...
My suspicion is that the ordering of components is messed up when Web Flow restores the view after resuming the flow. When using the above code in a simple JSF facelet (without using Web Flow), all is working fine.
I've debugged through the internals of Mojarra and Web Flow and can see that the order is being mixed in the buildView(FacesContext ctx, UIViewRoot view) method of FaceletViewHandlingStrategy when using Web Flow and not when using plain JSF.
See the attachments for the output of the example code. Before: ok.png, after clicking link: nok.png.
It seems like the main cause of this issue is the com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.adjustIndexOfDynamicChildren(). Adding a conditional breakpoint (on parent instanceof UIForm) shows how the child order is changed.
It appears that com.sun.faces.context.StateContext is tracking dynamic changes via a SystemEventListener inner class. The listener is added to the UIViewRoot when startTrackViewModifications is initially called. There seems to be a mismatch between listener used when the 1st postback is received and the one used after the redirect:
Postback is received
JSF View is restored and startTrackViewModifications starts
Event are processed
A redirect is issued
The redirect GET is received
The JSF View is restored but the previous StateContext$AddRemoveListerner appears to already be attached
There are now two StateContext in play, a new one that gets added and the previous one referenced via the AddRemoveListerner
Calls to startTrackViewModifications now only update the newer StateContext
In order to fix the issue we need to ensure that the StateContext.release() method is called before the redirect. This method will trigger unsubscribeFromViewEvent on the UIViewRoot. It seems that StateContext.release() is only called via StateManagerImpl.saveView. Since Spring Web Flow has its own statemanagement this method is currently not always called.
Stijn Lambert opened SWF-1577 and commented
When using Web Flow (2.3.1.RELEASE) in combination with JSF, I have a rendering problem when using a composite component of any kind and e.g. an <h:outputLabel /> component on 1 page after clicking a <h:commandLink />. The contents of the composite component are always displayed at the bottom of the page! When refreshing the page, rendering is fine again...
I can very easily reproduce this using this code:
My facelet:
testComponent looks like this:
My suspicion is that the ordering of components is messed up when Web Flow restores the view after resuming the flow. When using the above code in a simple JSF facelet (without using Web Flow), all is working fine.
I've debugged through the internals of Mojarra and Web Flow and can see that the order is being mixed in the buildView(FacesContext ctx, UIViewRoot view) method of FaceletViewHandlingStrategy when using Web Flow and not when using plain JSF.
See the attachments for the output of the example code. Before: ok.png, after clicking link: nok.png.
Thanks in advance for having a look!
Affects: 2.3.1
Attachments:
Sub-tasks:
The text was updated successfully, but these errors were encountered: