All ArticlesJSF

The problem with <t:saveState> and state serialization

JSF 1.2 doesn´t have a view scope that preserves the model for the time of being on the same view. That means you always have to decide between request oder session scope. There´s nothing in between. Many JSF developers overcome this problem by using <t:saveState> from MyFaces Tomahawk project. It is a very useful component but you should be aware of some common pitfalls when using JSF view state serialization in combination about it which are described in this article.

How does <t:saveState> work?

If you don´t want to put every managed bean in session scope (which is a good advice for keeping the session slight) you can use <t:saveState> to put a request scoped managed bean in view scope. This will preserve it´s data during the stay on the same view. Using <t:saveState> is very straightforward and helpful but it can lead to some problems if you´re not aware of what happens behind it. Especially when using the jsf feature of state serialization to reduce the size of the JSF view state, you might get into trouble which will be shown later on.

When using <t:saveState>, managed beans or bean values bound to it will be stored with the JSF view state after the last phase of the request lifecycle and will be restored on the first phase of the following request when posting back to the same view. The following code snipped shows an example for it´s usage:

...
<!-- put a bean in view scope -->
<t:saveState value="#{myRequestBean}" />
...
<!-- put a bean value in view scope -->
<t:saveState value="#{myRequestBean.whatEver}" />
...

So where and how is the JSF view state stored ?

JSF let´s you decide, wheather to keep the view state on client- or server side. If you´re interessed you can read more about server side state saving for Mojarra or Myfaces. Well, in practice most JSF applications use server side state saving to reduce bandwith between client and server which can be blown up by sending the the view state with requests or because it is the default setting.

So when using server side state saving it will be stored in session. This might sound a little bit strange, because when using <t:saveState> to minimize to need of session scoped beans they will be stored in session anyway! Well, the difference is that those beans only remain temporaly the session because JSF only keeps track about the last n view states. On n+1 view state it will be removed from session.

Because of this fact you should be aware, that <t:saveState> also might increase session memory consumption. So always look carefully at the beans (and their members) you bind to it.

Now it´s getting a little bit more complex and we´re getting to a real problem of <t:saveState> when being used in combination with seralizing the view state on the server side.

The trouble comes with state serialization

State serialization is a great feature to reduce the amount of memory consumption needed by JSF view state - especially when used in conjunction with state compression. So it´s a good advice to enable this feature with a context parameter in the web.xml:

<!-- MyFaces -->
<context-param>    
    <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
    <param-value>true</param-value>
</context-param>

<!-- Mojarra -->
<context-param>    
    <param-name>com.sun.faces.serializeServerState</param-name>   
    <param-value>true</param-value>
</context-param>

When configured, all managed beans and values bound to <t:saveState> must implement the Serializable interface because the view state (including the beans) will be serialized at the end of the request lifecycle.

Keep in mind that when a bean is serialized and deserialized, all of it´s members get´s serialized and deserialized as well (if not transient) - this also includes members that are session or application scoped beans. That´s why you have to pay attention in situations when beans use other beans like done in the following example:

We have a request scoped bean myRequestBean that utilizes an application scoped bean myApplicationBean:

public class myRequestBean
{
    // appBean is a member
    private MyApplicationBean appBean;
    ....

    public void setMyApplicationBean(MyApplicationBean  bean)
    {
        this.appBean = bean;
    }

    public MyApplicationBean getMyApplicationBean()
    {
        return this.appBean;
    }

     ...
}

We configure the beans by using the managed property feature:

<managed-bean>
    <managed-bean-name>myApplicationdBean</managed-bean-name>
    <managed-bean-class>...</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>
<managed-bean>
    <managed-bean-name>myRequestBean</managed-bean-name>
    <managed-bean-class>...</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    ...
    <managed-property>
        <property-name>myApplicationBean</property-name>
        <value>#{myApplicationBean}</value>
    </managed-property>
    ...
</managed-bean>

In the view, the request scope bean will be used in combination with <t:saveState>:

<t:saveState value="myRequestBean" />

What´s the problem with serializing here?

When bound to view state, myRequestBean will be serialized on request end. That means the bean itself and myApplicationBean - as being a member - will be serialized. This leads to the following problems:

  • An application scoped bean will be stored in view state (in a serialized form) and therefore put into the session (because the view state remains in session, see above)! Often application scoped beans contains large objects which are loaded only once per application and are never supposed to remain in the session
  • Serializing large objects on each request to the view that uses <t:saveState> can be cpu intensive.

On deserialization it´s getting even worse:

When restoring the bean from view state, it´s member myApplicationBean will be deserialized as well! During this processing the bean is not looked up from application scope but recreated as a new bean instance and set on myRequestBean. The result is that we have two instances of an application scoped bean at the same time:

  • the original one being in application scope
  • the other one recreated and set on myRequestBean during deserialization (will die when myRequestBean dies).

This should never be the case - an application scoped bean must be unique in the application! If your´re application scoped bean contains a lot of data your memory consumption might explode when having a lot of requests - remeber: serialization and deserialization happens on every request to a view containing <t:saveState value="myRequestBean">.

A workaround for this problem

One way to get around these problem is to not use state serialization at all by setting the flags in web.xml to false. This might not be a good solution in relation to memory consumption especially for large applications with many concurrent request. The preferred workaround is not to configure bean-relations as managed properties but lookup the beans from FacesContext instead - the example above could be rewritten like this:

public class myRequestBean
{
    ...

    public MyApplicationBean getMyApplicationBean()
    {
        // lookup myApplicationBean from facesContext (it is not a member)
        return FacesContext.getCurrentInstance().getExternalContext().
                         getApplicationMap().get("myApplicationBean");
    }

    ...
}

In general, it is better to use JSF´s managed property feature (inversion of control mechanism) configure managed beans - so there´s no need to lookup beans manually in your code but in this case it´s really not a good idea to use it.

 

added on 2010/06/28:

Concerning JSF 2.0 View Scope

In JSF 2.0 we have the view scope that will replace the usage of <t:saveState> considering managed beans. A look at current implementations (Mojarra 2.02, MyFaces 2.0) offers that the same problems might occure: ViewScoped objects will be bound the the UIViewRoot and might get serialized on calling UIViewRoot.saveState() with the view state (as the so called attached state).

About this Article

jan.ziegler: The problem with <t:saveState> and state serialization

written by: jan.ziegler on 15 Feb 2010

tags used: JSF

news stored under: JSF, JEE

share this article:

Comments (2)

Rohit M (posted on 23 Sep 2011, 12:09)

Good article ! Really clarifies lots of things about t:saveState

luxiang (posted on 22 Dec 2011, 10:38)

1fasdfasdfasdfasdf

Tell us what you think!