Why does JSF save component tree state?
Asked Answered
S

2

23

There appears to be a difference between managed bean state and component tree state. You can control managed bean state by using annotations like @RequestScoped and @SessionScoped, but it seems you don't have a choice in whether the component tree state is saved or not (although you can choose whether it is saved on the server or client).

It seems like component tree state should only be needed for the duration of a single request as a temporary data structure to help process a request. It should be rebuilt from scratch for each request. With JSF 2.0 partial state saving makes the situation better because only form data is saved, but I don't understand why having even form data from the previous request is useful.

If your application uses only request scope managed beans then it especially doesn't make sense to save component tree state between requests. Even if your application has session scope managed beans I would assume that the managed beans would hold the state and the component tree still wouldn't need to have any state between requests.

Soutine answered 8/9, 2011 at 13:53 Comment(0)
U
20

Because the component tree can be altered programmatically depending on the initial request. This is not necessarily reproduceable on the subsequent request whenever the form data has to be processed.

Further I have the impression that you think that the component tree also holds the model values. This is not true. It only holds references (by expression language) to the model values (the managed bean properties). The view state does not copy/duplicate/contain the model state. It's just a pure UI component tree. Perhaps your confusion is based on this. Note that the term "form data" is to be interpreted as submitted values and model values.

See also:

Unlikely answered 8/9, 2011 at 14:49 Comment(10)
Can you provide an example where the component tree cannot be rebuilt without the previous request state?Soutine
The components can be accessed by UIViewRoot#findComponent() and be altered programmatically by e.g. component.setAttribute("foo", "bar") or new children can be added by e.g. component.getChildren().add(newHiddenInput) and so on. This can happen in a managed bean or, more commonly, in a PhaseListener. True, this don't necessarily occur in trivial forms using basic JSF, but this can happen in the more complex forms or by more advanced component libraries. If you recreate new view instead of using the state as it was during render response of previous request, all those changes are lost.Unlikely
A more concrete example would help. Is there actually any reason to programmatically manipulate the component tree and know about it in future requests? Is there a particular component that does this for example?Soutine
For example, a PhaseListener which adds a "double-submit" prevention token to the form.Unlikely
A double submit prevention token could be saved in a managed bean with ViewScope or directly in the HTTPSession so it sounds like the component tree shouldn't absolutely have to be saved between requests. I've looked through the JSF specification, the JSF 2.0 Complete Reference Book by Ed Burns, and the Core JSF 3rd Edition book by Cay Horstmann and didn't find a single explanation for why the component tree must be saved. Odd, huh?Soutine
I was hoping there was a better explanation, but it doesn't look like there is so I'll accept yours. Saving the component tree is a lot of trouble for what seems like little advantage; oh well.Soutine
@Soutine I can't find even the little advantage! :) Can you please tell me what is it???Mcatee
@Mcatee - It doesn't make much sense to me either. I'll admit that you can construct a scenario where the component tree holds state used in future requests, but It seems to me it would be better in those scenarios to put the state in the managed bean facility. I guess the reasoning is just simply because the user can.Soutine
@Soutine I think its only usage can be with AJAX requests. After the termination of an asynchronous request the component tree can be used to check if there was a change in the state of a UI component during the request. I am only guessing... :)Mcatee
@Mcatee I have same trouble of understanding the necessity of saving the state of UI components. I reviewed some codes from MyFaces and RichFaces. However, I couldn't see a single reason to save the value of "class" attribute as a status and there are many others that don't make sense for me. At this point, I agree with you.Lockout
P
21

Adding to the previous answer, ever since JSF 2.0 something called partial state saving is used by default.

The default view description language in JSF (Facelets) creates the whole component tree from the original Facelet after every request and initializes the components from their corresponding tag attributes. It then marks the state.

Every subsequent state change is then remembered as a delta change, and it's this state that is actually being saved. It might just well turn out that there simply are no such changes, and then the view state is empty (because of a bug, the state was never truly empty, but that has been recently fixed. See http://java.net/jira/browse/JAVASERVERFACES-2203 for details)

So the big question is, what's actually in this state then when it's non-empty?

As BalusC already remarked, this could hold dynamic changes to the component tree. Those changes can either be initiated from backing beans, or from within static components. A simple example of the kind of component that does this dynamic changing is a table component that creates child column components based on the actual number of columns in a data set.

Another important usage for the view state is remembering values that have been changed inside components, but have not been pushed into the model. This can be such things as flicking a switch in a switch component, moving a slider in a dial component etc.

One particular example is the viewParam component, which remembers the request parameter (query string parameter for GET or non-faces POST parameter) with which it was initialized. See this for some more info about that: http://arjan-tijms.omnifaces.org/2011/07/stateless-vs-stateful-jsf-view.html

There is also a strong relation with stateful components remembering UI state and conversion or validation that fails. In this case, the UI components will remember the values entered by the user, and will remember that there was a conversion/validation error.

Yet another usage for the state is optimization. Some components calculate values that they deem to be expensive to calculate and store these in the view state. For instance, UIInput components do this after the first post-back:

private boolean validateEmptyFields(FacesContext ctx) {

    if (validateEmptyFields == null) {
        ExternalContext extCtx = ctx.getExternalContext();
        String val = extCtx.getInitParameter(VALIDATE_EMPTY_FIELDS_PARAM_NAME);

        if (val == null) {
            val = (String) extCtx.getApplicationMap().get(VALIDATE_EMPTY_FIELDS_PARAM_NAME);
        }
        if (val == null || "auto".equals(val)) {
            validateEmptyFields = isBeansValidationAvailable(ctx);
        } else {
            validateEmptyFields = Boolean.valueOf(val);
        }
    }

    return validateEmptyFields;

}

After this validateEmptyFields is stored in the view state so it doesn't have to be calculated again upon the following form submits. An improvement would be if users can choose between re-calculating or storing (the well know time-space optimization).

The very concept of state is what has plagued web application development since its early conception. Everyone wants to have interactions that are essentially stateful, yet almost nobody wants to handle it or even think about it.

JSF has been trying to provide an answer here, but it's obviously not perfect and there's room for improvement. JSF's insistence on being able to restore view state (even empty view state) can be troublesome, although as was mentioned in another answer it does provide an implicit protection against CSRF. JSF 2.2 will get more explicit CSRF protection (see e.g. http://arjan-tijms.omnifaces.org/p/jsf-22.html#869), so maybe we will see some change here in the future.

Having an option to turn off state per component and having an easy hook to restore state incase the framework can't (as in ASP.NET) might also be helpful.

Pollaiuolo answered 31/10, 2011 at 17:45 Comment(2)
Thanks for adding more clarification and examples. I understand a little better now. I'm still not convinced that saving component tree state is the right thing to do since it seems you could always use the managed bean facility to hold state. I don't see why state must be saved to redisplaying values entered by the user that fail conversion/validation - just server-side forward the post to the original view.Soutine
Sometimes the usage of view state is indeed debatable, I'm about to create some JIRA issues for the EG asking to address this. Nevertheless, managed beans are not always the right answer. A lot of this kind of state concerns internal details of the components and the burden of handling this should IMHO not be enforced on the user. Another category that I didn't mention yet are optimizations (see updated answer)Pollaiuolo
U
20

Because the component tree can be altered programmatically depending on the initial request. This is not necessarily reproduceable on the subsequent request whenever the form data has to be processed.

Further I have the impression that you think that the component tree also holds the model values. This is not true. It only holds references (by expression language) to the model values (the managed bean properties). The view state does not copy/duplicate/contain the model state. It's just a pure UI component tree. Perhaps your confusion is based on this. Note that the term "form data" is to be interpreted as submitted values and model values.

See also:

Unlikely answered 8/9, 2011 at 14:49 Comment(10)
Can you provide an example where the component tree cannot be rebuilt without the previous request state?Soutine
The components can be accessed by UIViewRoot#findComponent() and be altered programmatically by e.g. component.setAttribute("foo", "bar") or new children can be added by e.g. component.getChildren().add(newHiddenInput) and so on. This can happen in a managed bean or, more commonly, in a PhaseListener. True, this don't necessarily occur in trivial forms using basic JSF, but this can happen in the more complex forms or by more advanced component libraries. If you recreate new view instead of using the state as it was during render response of previous request, all those changes are lost.Unlikely
A more concrete example would help. Is there actually any reason to programmatically manipulate the component tree and know about it in future requests? Is there a particular component that does this for example?Soutine
For example, a PhaseListener which adds a "double-submit" prevention token to the form.Unlikely
A double submit prevention token could be saved in a managed bean with ViewScope or directly in the HTTPSession so it sounds like the component tree shouldn't absolutely have to be saved between requests. I've looked through the JSF specification, the JSF 2.0 Complete Reference Book by Ed Burns, and the Core JSF 3rd Edition book by Cay Horstmann and didn't find a single explanation for why the component tree must be saved. Odd, huh?Soutine
I was hoping there was a better explanation, but it doesn't look like there is so I'll accept yours. Saving the component tree is a lot of trouble for what seems like little advantage; oh well.Soutine
@Soutine I can't find even the little advantage! :) Can you please tell me what is it???Mcatee
@Mcatee - It doesn't make much sense to me either. I'll admit that you can construct a scenario where the component tree holds state used in future requests, but It seems to me it would be better in those scenarios to put the state in the managed bean facility. I guess the reasoning is just simply because the user can.Soutine
@Soutine I think its only usage can be with AJAX requests. After the termination of an asynchronous request the component tree can be used to check if there was a change in the state of a UI component during the request. I am only guessing... :)Mcatee
@Mcatee I have same trouble of understanding the necessity of saving the state of UI components. I reviewed some codes from MyFaces and RichFaces. However, I couldn't see a single reason to save the value of "class" attribute as a status and there are many others that don't make sense for me. At this point, I agree with you.Lockout

© 2022 - 2024 — McMap. All rights reserved.