Components don't directly go into an inconsistent state from being state saved. Since there are several scenarios where the execution portion of a lifecycle may not happen, from an initial GET and from validation failures, there are cases where components need to do processing during rendering, and will need to have the results of that processing state saved, so that on the next lifecycle they'll be in a consistent state. When getViewState triggers state saving before the component has even rendered, and then there is no state saving at the end of the rendering, then that state gets lost. This might be internal state that we don't want exposed as a property, so there is no application work-around of using a ValueExpression. So for the components, the solutions are either for getViewState to get called after they render, or for state saving to happen again, after all components have been rendered.
For IPCK-418, the issue also that getViewState is getting called too early, in that we have not yet returned the ValueExpressions to their correct real values by the time state saving is getting triggered.
So, if we could just sequence things like this, everything should work:
1. Render the whole component tree
2. Return the partial submit ValueExpressions to their original values
3. Call getViewState
4. Transmit the response back to the client
This might be possible by using the JavascriptRunner to execute the javascript that FixViewState needs rendered, after steps 1 and 2, but before step 4. We might not need to actually render script tags into the forms themselves, we just need script rendered per form, and that was the most straight forward way of accomplishing it. But maybe it wasn't actually, since we need to update all forms, even if we've only done a partial sub-tree rendering in one form.
Checked in a fix that changes the logic so that the call to getViewState() happens after rendering is complete.
The new strategy is handled much like we handle the "extensions" scripts. During rendering, we track the forms that are affected by storing their ids in the FacesContext attributes map. Then, during DOMPartialViewContext.processPartial, we check for any ids and write out an eval script that contains the form ids and the new ViewState value which is aligned with how we also render out the extensions for the components.
I did some basic testing using Mojorra and MyFaces as well as some portlets. If further testing reveals a problem we can re-open the case.