What makes an Object serializable - java

I have an object with a HashMap field and a few methods that I am trying to serialize. However, at runtime, I am getting a java.io.NotSerializableException.
I was checking to see if HashMaps could be serialized and from what I have read they are so I am not sure what the problem is.
I was just wondering what makes an object be able to be serialized and why would this object that seems to only have fields that can be serialized not be able to as well.

This is defined in the Java platform Spec here:
https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html
The basic rules are these:
"A Serializable class must do the following:
Implement the java.io.Serializable interface
Identify the fields that should be serializable (Use the
serialPersistentFields member to explicitly declare them serializable
or use the transient keyword to denote nonserializable
Have access to the no-arg constructor of its first nonserializable
superclass"
Broadly, in the absence of any indication to the contrary, and field that is not explicitly marked "transient" is a candidate for serialization.
The entire object graph from the target object downwards has to be serializable, or nothing is. That is, every field that references an object (not a primitive) must reference a serializable object.

Related

Why Fields in a "Serializable" class should either be transient or serializable?

In our application, for one class(which is Serializable) sonar is complaining - Fields in a "Serializable" class should either be transient or serializable.
That class is not serialized anywhere in our application. But I am not sure why it implements serializable because that class was written long time ago.
As per the Sonar doc , Fields in a Serializable class must themselves be either Serializable or transient even if the class is never explicitly serialized or deserialized.
But I didnt find any exact reason behind this.
Could you please explain why its harmful if Fields in a "Serializable" class is not transient or serializable ? if the class is never explicitly serialized or deserialized then what is the harm here ?
I was going through Fields in a “Serializable” class should either be transient or serializable, but I didnt find proper answer of my question. I found below statement but didnt understand much
For instance, under load, most J2EE application frameworks flush objects to disk, and an allegedly Serializable object with non-transient, non-serializable data members could cause program crashes, and open the door to attackers. In general a Serializable class is expected to fulfil its contract and not have an unexpected behaviour when an instance is serialized.
Thanks
Serialization, transform an object to a stream of bytes. The object has to be serializable, and all its fields serializables because the serialization process serializes the object with all its fields, but if one field should/could not be serializable, it has to be explicitely marked as transient so it will be ignored. If its not ignored (marked as transient) an exception of type NotSerializableException will be thrown at serialization.
If your class objects will not be serialized at some point, there is no need to implemet Serializable.

Should All Class References in a Serializable Object Implement Serializable?

I'm trying to save the neural network after training by implementing a Serializable object, and this class contains Layer and Node class references.
My question is: should I implement Serializable in these(layer,node) two classes as well, in order to be able to save and load instances of the Neural Network class successfully without any problem, especially { java.io.NotSerializableException } ?
Every object that you intend to store/load using serialization must implement Serializable. This includes any member fields inside the objects that you are serializing.
The only exception are fields that you don't think that you will need to store for later use when you deserialize. You can mark these fields as "transient," e.g.
private transient int foo;
Any field marked as transient will NOT be stored as part of the serialized object, and when the object is later deserialized will be set to the default value (i.e. 0 for most primitives, false for booleans, and null for objects).

Is determining what is transient a trial and error?

Assume I create a class Foo, whose instance variables are instances of different class's. Eg:
class Foo implements Serializable {
BarA barA;
BarB barB;
.
.
BarZ barZ;
}
I understand that when I serialize, I need to all the Bar's to be serializable, else I need to mark them as transient.
But How to know which one's should be marked as transient ? Is this trail and error ?
I understand that when I serialize, I need to all the Bar's to be serializable, else I need to mark them as transient.
Your understanding is incorrect.
Flagging a field as transient causes it to not be stored when an object is serialized. As such, you should only do this for fields whose values are fundamentally impossible to serialize (e.g, a network connection), or fields whose values can be discarded and recreated later (e.g, a cache, or a reference to an application global). Otherwise, the serialized representation of this object will be incomplete.
While it is often the case that a non-serializable object will associated with a transient field, this is not always the case. Understand what "transient" means before you go throwing it around just to make your code run!
You should make sure that all fields that decide the state of your Foo object are serializable, the rest can be transient.
Noone can answer which fields belong to which category but you, the developer.
Even if you are using an external library with no source code and obfuscation, you can write code that using reflection will tell you if it or one of its parent classes and interfaces implements Serializeable.
So there cannot be a situation in which you design code and don't know what you are using.

Java: what happens when an already loaded class is deserialized

Let's say class com.Foo is loaded from a JAR and later a class with the same name com.Foo, but different definition (other fields) is deserialized (e.g loaded either from DB, or received from a remote call).
What could be the consequences? Will the new received class have any impact? Let's say that the class is used in other parts of the application, being persisted in DB and serialized/JSON encoded later.
If you deserialize a Class<?> object then the class with the fully-qualified class name gets loaded. If it is already loaded you will get the reference to that class.
I think that for a complete answer you should read Java Object Serialization Specification
Here are some quotations from the spec that I think are interessting:
1.1 Overview
Special handling is required for arrays, enum constants, and objects of type Class, ObjectStreamClass, and String. Other objects must implement either the Serializable or the Externalizable interface to be saved in or restored from a stream.
2. Object Output Classes
If the object is a Class, the corresponding ObjectStreamClass is written to the stream, a handle is assigned for the class, and writeObject returns.
3. Object Input Classes
If the object in the stream is a Class, read its ObjectStreamClass descriptor, add it and its handle to the set of known objects, and return the corresponding Class object.
You have the wrong imagination of how Serialization works. You can write a Class instance to an object stream just like other objects but this will not write the byte code of that class nor its definition to the stream. It just creates a symbolic reference to the class which is resolved like any other class reference of the stream: by using its symbolic name trying to resolve it in the context of the class deserializing it. It does not create a new class.
In fact, an instance of java.lang.Class creates even less dependencies to the actual class than writing an instance of it. The instance depends on the serialized form, e.g. the non-transient field of the class, while the symbolic reference represented by an instance of java.lang.Class does not depend on it.
The compatibility between the class present when writing a stream and the class present when deserializing it is determined by the serialVersionUID if it doesn’t match, deserialization will always fail with an exception. If it matches, the implementation will try its best to recover. Fields not present in the stream get their default values, stream fields not present in the actual class and any other unprocessed extra data will be ignored.

Serialize static attributes in Java

What happens if i'll try to serialize an attribute which is static?
thanks
From this article:
Tip 1: Handling Static Variables
Java classes often hold some
globally relevant value in a static
class variable. We won't enter into
the long history of the debate over
the propriety of global variables -
let's just say that programmers
continue to find them useful and the
alternatives suggested by purists
aren't always practical.
For static variables that are
initialized when declared,
serialization doesn't present any
special problems. The first time the
class is used, the variable in
question will be set to the correct
value.
Some statics can't be initialized this
way. They may, for instance, be set by
a human during the running time of the
program. Let's say we have a static
variable that turns on debugging
output in a class. This variable can
be set on a server by sending it some
message, perhaps from a monitor
program. We'll also imagine that when
the server gets this message, the
operator wants debugging turned on in
all subsequent uses of the class in
the clients that are connected to that
server.
The programmer is now faced with a
difficulty. When the class in question
arrives at the client, the static
variable's value doesn't come with it.
However, it contains the default
static state that's set when the
class's no-argument constructor is
called by writeObject(). How can the
client programs receive the new
correct value?
The programmer could create another
message type and transmit that to the
client; however, this requires a
proliferation of message types,
marring the simplicity that the use of
serialization can achieve in
messaging. The solution we've come up
with is for the class that needs the
static transmitted to include a
"static transporter" inner class. This
class knows about all the static
variables in its outer class that must
be set. It contains a member variable
for each static variable that must be
serialized. StaticTransporter copies
the statics into its member variables
in the writeObject() method of the
class. The readObject() method
"unwraps" this bundle and transmits
the server's settings for the static
variables to the client. Since it's an
inner class, it'll be able to write to
the outer class's static variables,
regardless of the level of privacy
with which they were declared.
And from another article:
Static or transient data
However, this "ease" is not true in
all cases. As we shall see,
serialization is not so easily applied
to classes with static or transient
data members. Only data associated
with a specific instance of a class is
serialized, therefore static data,
that is, data associated with a class
as opposed to an instance, is not
serialized automatically. To serialize
data stored in a static variable one
must provide class-specific
serialization.
Similarly, some classes may define
data members to use as scratch
variables. Serializing these data
members may be unnecessary. Some
examples of transient data include
runtime statistics or hash table
mapping references. These data should
be marked with the transient modifier
to avoid serialization. Transient, by
definition, is used to designate data
members that the programmer does not
want or need to be serialized. See
Java in a Nutshell, page 174: mouse
position, preferred size, file handles
(machine specific (native code)).
When writing code if something is
declared transient, then this triggers
(to programmer) necessity of the
posibility of special code for
serialization later.
To serialize an object, you create
some sort of OutputStream object and
then wrap it inside an
ObjectOutputStream object. At this
point you only need to call
writeObject() and your object is
magically serialized and sent to the
OutputStream. To reverse the process,
you wrap an InputStream inside an
ObjectInputStream and call
readObject(). What comes back is, as
usual, a handle to an upcast Object,
so you must downcast to set things
straight. If you need to dynamically
query the type of the object, you can
use the getClass method. Specifically
dk.getClass.getName() returns the name
of the class that dk is an instance
of. I.e., this asks the object for the
name of its corresponding class
object. (Hmmm, True, but what about
syntax? I still need to know what it
is to declare it...too bad) (C++ can
do this in one operation (dynamic_cast
(gives null if wrong type)), java can
use instanceof operator to check if it
is what I think (see Core Java, Ch5
Inheritence, Casting section)
Yes, we can defnitely serialise the static variable, but we wont be able to get any purpose of serialisation on the static variables.
Why because the Static variables are not bounded to any objects in scope.
We serialize objects to store them so they can retrieved later for any use.
Only the Transient varibles you cant make them to get serialised.
You can serialize the value of a static variable / attribute. But strictly speaking, you don't serialize a variable or attribute in its own right, whether it is class level, instance level, or local to a method.
Normally the instance level attributes of an object are serialized as part of the parent object; i.e. the object that they are attributes of. If you translate that to class level attributes, then the notional parent is the class. While there is a runtime object that denotes this class (i.e. the java.lang.Class returned by this.getClass()), this object is not serializable. So from that perspective, a class level (static) attribute is not serializable.

Categories

Resources