What causes this kind of error in Tomcat?
SEVERE: Exception loading sessions from persistent storage
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException:
bean.ProjectAreaBean
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1333)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at java.util.ArrayList.readObject(ArrayList.java:593)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(
DelegatingMethodAccessorImpl.java:25)
Serializable
If you're getting a NotSerializableException
like follows,
java.io.NotSerializableException: bean.ProjectAreaBean
then it simply means that the class as identified by the fully qualified name in the exception message (which is bean.ProjectAreaBean
in your case) does not implement the Serializable
interface while it is been expected by the code behind. Fixing it is relatively simple, just let the class implement the Serializable
interface.
package bean;
import java.io.Serializable;
public class ProjectAreaBean implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}
The serialVersionUID
field is not necessary, but strongly recommended as this maintains the binary compatibility between different versions of the class and the serialized representations of its instances. So when you add later a new serializable field to the class, then you'd need to change the serialVersionUID
field (usually just incrementing it by 1 is sufficient) to prevent problems during deserialization of an instance of an older version of the class. IDEs like Eclipse also offer an option to (re)generate the serialVersionUID
value which is basically a hash computed based on all fields.
transient
If your Serializable
class contains in turn a field/property referencing an instance of another class which can absolutely not be made Serializable
(usually, these represent resources, such as InputStream
, Connection
, etc), then you'd need to mark it transient
. This way it will be skipped during serialization of the class.
private transient SomeObject thisWillNotBeSerialized;
You need to understand that after deserialization this field would always become null
. Note that the class' constructor and initialization blocks are not invoked during deserialization. If you'd like to have finer grained control over serialization and deserialization, then override the readObject()
and writeObject()
methods. You can find concrete examples in below links:
As to the why you need to worry about serialization, this is because most Java servlet containers like Tomcat require classes to implement Serializable
whenever instances of those classes are been stored as an attribute of the HttpSession
. That is because the HttpSession
may need to be saved on the local disk file system or even transferred over network when the servlet container needs to shutdown/restart or is being placed in a cluster of servers wherein the session has to be synchronized.
In order to be able to save Java objects on the local disk file system or transfer them over network, they have to be converted to a byte stream first (basically: a byte[]
or an InputStream
) and that is only possible if the class behind the object implements Serializable
. The Serializable
interface itself doesn't really do anything, it's merely a marker interface. The code behind merely does an instanceof Serializable
check on the session attribute to act accordingly.