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.