Hi Andrej,

On Wed, 2009-01-28 at 19:36 +0100, Andrej Konkow wrote:
> Hi all,
> 
> I have following problem:
> I have a jsf-page using a simple requestscoped backingbean, without any 
> customcomponents etc..
> I am using t:saveState to keep data between the requests.
> The backingbean is inheriting from a common base class in which a 
> HtmlInputDate is being used for an attributetype.
> Everything is working fine as long as I have defined the following in my 
> web.xml:
> 
>      <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
>      <param-value>false</param-value>
> 
> When changing this config to "true" I get the following:
> 
> [2009-01-26 20:14:25,968] [http-8080-2] [ERROR] 
> javax.faces.webapp._ErrorPageWriter - An exception occurred
> javax.faces.FacesException: java.io.NotSerializableException: 
> org.apache.myfaces.custom.date.HtmlInputDate
> 
> I'm not quite sure whether this is a bug or a feature but I was not aware 
> that backingbeans should implement the Stateholder-interface...
> I had a short discussion in: 
> https://issues.apache.org/jira/browse/MYFACES-2141
> 

No, backing beans do not need to implement StateHolder. That is
necessary if you create a custom component (which is what I thought you
were doing because I didn't read your problem description carefully
enough).

What you need to do in your case is declare the member you store the
component-binding in as "transient". Then when the view is serialized
and the backing bean gets serialized with it (because of t:saveState),
the java standard serialization does not try to serialize the
non-serializable member. When the view is restored on the next postback
jsf will reinitialize the binding value so marking this member as
transient should be all that you need.

Unfortunately in this case, it means modifying the "common base class"
you are inheriting from; hope you can do that. If you cannot do that,
then you might have to customize the serialization process (create a
writeObject method or similar) to first set the binding to null before
invoking normal serialization.

Effectively you are breaking the rule that "bindings should only be to
request-scoped beans" by using t:saveState which makes the bean scope
something longer than just "request". Nulling out the binding before
serializing the bean fixes this..

> Could anybody please bring light into my thoughts? :-)
> 
> The reason for me to try this change was that pages that work fine in a 
> normal clickflow throw an exception
> when waiting, let's say 90 min.
> javax.servlet.ServletException /jsp/app/time/projecttimes.jsfNo saved view 
> state could be found for the view identifier: /jsp/app/time/projecttimes.jsf

Unfortunately, I don't think that using t:saveState will help you here
anyway. The problem looks like the http session is timing out (90
minutes) so when the postback occurs, the old saved view is gone.
Putting your backing bean into the saved view won't change anything;
when the session goes and therefore the saved view is gone, you will
always get this error message.

This SERIALIZE_STATE_IN_SESSION flag just controls whether the data
stored in the session is "compressed" (serialized) or not. Leaving this
at the default value (true) is good because it also tests at the end of
each request that the view state *can* be serialized. Http-sessions can
be serialized in a number of situations: 
 * servlet engines can flush them to disk when memory is low
 * clustered servers need to serialize sessions to transfer them between
machines in the cluster
 * server hot-restart feature serializes sessions on stop and
deserializes them on restart.
If you set SERIALIZE_STATE_IN_SESSION to false, then the app appears to
work until you try to do one of the above. Then you get a big surprise.
It is better to have this set to true so that the program tells you
about potential problems earlier.

What I often do is embed a simple piece of javascript into pages which
sends a "ping" request to the server every minute or so. Then http
sessions will never time out while the browser is open. The http-session
timeout can then be set to a nice low value, like 10 minutes, which
helps ensure that memory is cleaned up when people really do leave the
site.

Or you could use client-side state saving. Then if the session times
out, it doesn't matter (as long as you have no other important data in
the session) because the saved view tree (including your bean because of
t:saveState) is part of the data posted by the client.

Regards,
Simon


Reply via email to