Going through an abstract in a book, I came across this:
On the server side, the state can be stored as a shallow copy or as a
deep copy. In a shallow copy, the state is not serialized in the
session. By default, JSF Mojarra uses shallow copy.
I seriously couldn't understand this.
Since in the above case, we will have-
javax.faces.STATE_SAVING_METHOD set to server,
and an input hidden field javax.faces.ViewState with a value somewhat like this "2870966362946771868:-8449289062699033744".
Obviously, the server must have maintained internally an state corresponding to the above hidden field.
But going by the abstract, if the state is not serialized in the session, then where it is?
Furthermore, I have noticed one thing that if my Managed bean(ViewScoped) is not implementing marker interface Serializable with STATE_SAVING_METHOD set to server, then in Mojarra, the NotSerializablEexception doesn't occur, while in MyFaces it does.
But going by the abstract, if the state is not serialized in the session, then where it is?
It exist of references to instances already in the HTTP session which in turn is not necessarily serialized.
The key context param for this is javax.faces.SERIALIZE_SERVER_STATE which defaults in MyFaces to true and in Mojarra to false. When set to true, you will sooner see NotSerializableException on artifacts which are mistakenly not Serializable. Otherwise, you're dependent on server configuration. For example, Tomcat by defaults serializes the entire HTTP session including all its attribtues during a server restart. Some servers, particularly those running in cluster, can even be configured to serialize entire HTTP sessions during runtime. In such cases you would also see NotSerializableException during restart or failover.
Mojarra has plans to make javax.faces.SERIALIZE_SERVER_STATE setting default to true as per 2.3, particularly because this setting would proactively prevent unforeseen developer mistakes such as assigning non-serializable instances of JSF artifacts such as UIComponent or even FacesContext as properties of a non-requestscoped bean. It would otherwise result in problems as Stuck thread at UIComponent.popComponentFromEL, Java Threads at 100% CPU utilization using richfaces UIDataAdaptorBase and its internal HashMap and java.lang.IllegalStateException at com.sun.faces.context.FacesContextImpl.assertNotReleased.
On the other hand, in older MyFaces versions, this setting broke EJBs injected in serializable managed beans due to the wrong classloader being used to resolve EJB proxies during deserialization. This was fixed in MyFaces 2.0.15 and 2.1.9 as per MyFaces issue 3581. See also #EJB in #ViewScoped #ManagedBean causes java.io.NotSerializableException.
Related
I'm wondering why there is no single notice about the importance of immutability property when storing serializable objects in the HTTP session? I tried to check the JSF and Servlet API specifications but couldn't find anything related.
I've seen a specific problem in the case of JSF based clustered application where #SessionScoped managed bean is mutable i.e. user-modified parameter is stored as a field of this managed bean.
Trouble begins when the node "owning" the session (thanks to stickiness requirement in servlet API specs) dies and different node starts to take over serving the session, the latest state is lost. In fact, only the initial state is replicated. I believe this is because managed beans are placed in session (and replicated to backup nodes) only when they are created for the first time, at least this is confirmed by my tests performed on Websphere.
While one can debate whether this is a good design or not, JSF and even Servlet API still allows it to happen.
I also found some note in Oracle docs:
As a general rule, all session attributes should be treated as immutable objects if possible. This ensures that developers are consciously aware when they change attributes. With mutable objects, modifying attributes often requires two steps: modifying the state of the attribute object, and then manually updating the session with the modified attribute object by calling javax.servlet.http.HttpSession.setAttribute(). This means that your application should always call setAttribute() if the attribute value has been changed, otherwise, the modified attribute value will not replicate to the backup server.
Apart from manually updating the attribute as described above, is there any clean solution, preferably in an idiomatic JSF way?
In WebSphere Liberty, there is a property called
writeContents = "GET_AND_SET_ATTRIBUTES"
for the mutable session objects. For details, please see:
https://github.com/OpenLiberty/open-liberty/issues/2802
https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.liberty.autogen.nd.doc/ae/rwlp_config_httpSessionCache.html
Same property apply for database persistence.
I have done a small experiment with #FlowScoped beans, whose purpose, as I understand, is to make easier creating "wizard-type" web applications, gradually accumulating data over a sequence of pages, then, once all the data is ready, writing it to the persistent storage (this is just an example, nothing prevents of course to write to the persistent storage during intermediate steps). As I saw, the calls to a #FlowScoped bean are not synchronized, and thus there is in principle the possibility of corrupting the data stored in the bean (by doing a double submit, or launching by any other means two almost simultaneous HTTP requests, which invoke the methods of the bean). This unlike #ConversationScoped beans the calls to which are synchronized.
What puzzles me is that about #SessionScoped beans I have found several links which speak about the need to synchronize the access to a #SessionScoped bean (or recommending not to use them at all, apart from user data which changes rarely), but I have not found anything like that about #FlowScoped beans.
What is considered then to be a "best practice" for using #FlowScoped beans? Am I missing something?
EDIT
#FlowScoped seems, at least to me, to be motivated in part by Spring WebFlow, with which I have some experience, and which, as I know, offers integration with JSF 2 (not all JSF 2.2 features seem to be implemented, but it seems that PrimeFaces is usable, for example). I know that Spring WebFlow + JSF is actually used in "real world" applications, and the issue of thread safety of flow scoped objects is handled there elegantly together with double submit issues (flow execution id must be supplied with each HTTP request, and it expires and a new one is returned after a HTTP request which invokes a Spring WebFlow "action" method: therefore one cannot invoke concurrently more than one "action" method for the same user and flow id).
So I want to understand, what is the best practice in the case of JSF 2.2 if I wish to use the #FlowScoped beans to construct an application "flow" (without using Spring WebFlow). Do I really need to synchronize the access to #FlowScoped beans myself, or there is some standard way to deal with such issues?
I have a simple jsf 2.1 that used to work fine on Java EE 6 using primefaces 3.4.
When I migrated to glassfish 4.0 and primefaces 5.1 I've got the following exceptions each time I redeploy the project on Netbeans:
java.io.NotSerializableException: org.primefaces.model.DefaultStreamedContent
java.io.NotSerializableException: org.primefaces.component.datatable.DataTable
Even if this exception is thrown, the project is deployed and run correctly!
What could be wrong?
You've declared those types as a property of a view or session scoped managed bean. You should absolutely not do that. You should declare them as a property of a request scoped bean.
View and session scoped beans must be Serializable because view scoped beans are reused/shared across multiple requests on the same view in the same session, and session scoped beans are reused/shared across multiple requests in the same session. Anything tied to a specific HTTP session must be Serializable, because it enables the server to store sessions on disk, so it could be shared among other servers in a cluster, or survive server restarts.
The DefaultStreamedContent (and the InputStream it is wrapping, if any) may absolutely not be created and assigned as a view/session scoped bean property, not only because it's not serializable, but also because it can be read only once. You need to create this in the getter method only. This is indeed a rather special case which is fleshed out further in this answer: Display dynamic image from database with p:graphicImage and StreamedContent
The DataTable is a JSF component which you most likely referenced via binding attribute. It may absolutely not be assigned as a view/session scoped bean property, because UI components are inherently request scoped. Reusing the same UI component instance across multiple restored views in the same session may cause its state being shared across multiple requests (NOT threadsafe thus!) and/or potential "Duplicate Component ID" errors. See also a.o. How does the 'binding' attribute work in JSF? When and how should it be used?
NotSerializableException is thrown when an instance of a class must implement the Serializable interface.
If the class that throws the exception does not belong to a third-party library, find the class and make it implement the serializable interface.
If you do not want to serialize the objects in the class, you can mark the objects as transient, to make the serializable runtime ignore the objects.
You can read about it here
I can't understand how serialization works in session scoped JSF managed beans. Why is implementation of Serializable interface important while creating a session scoped JSF managed bean?
#SessionScoped beans are ultimately stored in the user's HTTP session.
This means that when a Java EE deployment implements a session preservation scheme (for example, tomcat will attempt to save current sessions to a .ser file on server shutdown, if the deployer so chooses), those session-scoped beans would also be part of the payload that will be persisted.
A session scoped bean that isn't serializable becomes a problem here as it renders the entire HTTP session that it is a part of, un-persistable (any attempt to serialize an object that contains an unserializable member will cause a NotSerializableException, except with some special handling)
Incidentally, that means that even if your session-scoped bean implements Serializable, all its member variables must either be serializable or be marked transient.
In short, the entire object graph of a given HTTP session that is liable to be persisted via serialization, must either be marked as serializable or transient
Read more:
Why does Java have transient fields?
JavaBean recommendations on serialization
Just extending the answer of kolossus. Most of Servlet Containers like Tomcat may use an strategy of storing the Session data to physical memory, in case if restart or web app reload.
Well the usual way to store/persist Java instances/Objects is using ObjectoutputStream, which indeed requires the Object/instance to be persisted, to implement the Serializable interface.
You can see that its mentioned in Tomcat docs that:
Whenever Apache Tomcat is shut down normally and restarted, or when an
application reload is triggered, the standard Manager implementation
will attempt to serialize all currently active sessions to a disk file
located via the pathname attribute. All such saved sessions will then
be deserialized and activated (assuming they have not expired in the
mean time) when the application reload is completed.
Link for doc.
My question is related to this one (and probably others):
#PreDestroy never called on #ViewScoped
As stated there, there's no trivial solution to either have view-scoped beans destroyed upon navigation and the same seems to hold true for when the session expires.
What would a non-trivial approach to release (calling the #PreDestroy method) JSF view-scoped beans look like, or more specifically as soon as the session expires?
I'm using Java EE 6 and Mojarra 2.1.x on GlassFish 3.1.2.
Create a #SessionScoped bean to hold the resources (in some collection/array?) and inject it in the #ViewScoped bean and then rely on the #PreDestroy of the session scoped bean.
True, this way the resources live a little longer than you want, but that's the most easy and reliable solution you can get. If you want to keep the #PreDestroy in the view scoped bean, then you'd need to somehow make sure that the enduser always performs navigation by a HTTP POST request on exactly this view scoped bean. You can't reliably guarantee that (the enduser's PC might crash and so on).