how does serializable work in java? - java

If I have an instance of a class that I store in a session I need to make it serializable. This class has a static variable, will this be serialized in every instance stored?
The static variable is a reference to a cache containing a lot of data in the background. Will all of this data be serialized? If so, it seems preferable to make this variable transient and re-fetch the cache instance each time the instance is restored. Maybe not store the cache instance at all in the class.
Will the constructor execute when a class is restored from a serialized state? if not is there any other method I can use to re-instate a transient variable?

This class has a static variable, will
this be serialized in every instance
stored?
No. According to the Java Object Serialization Specificaiton: "Default serializable fields of a class are defined to be the non-transient and non-static fields."
Will the constructor execute when a class is restored from a serialized state?
No. Deserialization bypasses constructors (unless you have a non-serializable superclass).
if not is there any other method I can use to re-instate a transient variable?
You can use the readObject() method for that, as described in the Serializable API doc.

static and transient fields are not serialized. No, the constructor is not called. For more details, please check this out: http://java.sun.com/developer/technicalArticles/ALT/serialization/

Related

Singleton Class Serialization

My singleton class be like this:
public class SerializableSingleton implements Serializable {
private static SerializableSingleton instance = new SerializableSingleton();
private SerializableSingleton() {
System.out.println("Constructor is being called");
}
public static SerializableSingleton getInstance() {
return instance;
}
}
Now it's written on the web that when we deserialize this singleton object, it will give a new instance back and not the previous one, and in order to fix this, use the readResolve() method.
But my question is - How is it even possible? When a static class member can't be serialized, how does the question of deserializing it comes at all? and it is all over the net?
Since the singleton object is static:
private static SerializableSingleton instance = new SerializableSingleton();
How is an instance getting serialized in the first place?
Serialization bypasses a lot of things in the language and even does some stuff that is not even possible with ordinary reflection.
When an object is serialized, it's class name and all instance fields (that are not transient) are written to the stream.
The magic happens when deserializing an object.
First, a new instance of the class is allocated.
To do that, the no-argument constructor of the first non-serializable superclass is called. The constructor of the serializable class (and serializable superclasses) are skipped. How? Magic.
Then all instance fields of the serializable classes are set.
(This step can be customized using a private void readObject(ObjectInputStream) method)
Lastly, a readResolve() method is called - if such a method exists. It's result is used as the result of deserializing the object.
(This does not apply to records, instances of java.lang.Class, java.lang.String, java.lang.Enum...)
In your example, this means that a new instance of your SerializableSingleton is created - bypassing your private constructor and instead calling java.lang.Object.<init>() - so you won't see the "Constructor is being called" output.
Now you have two instances of an "Singleton". To restore the original singleton semantics (there only ever exists one single instance of that class), we replace the just-deserialized-instance with the canonical instance:
private Object readResolve() {
return getInstance();
}
tl;dr: Java's serialization is complicated and sometimes indistinguishable to black magic. Using java's serialization opens the door to some surprising behaviors.
As the docs say:
By implementing the readResolve method, a class can directly control
the types and instances of its own instances being deserialized. The
method is defined as follows:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
And:
... For example, a Symbol class could be created for which only a
single instance of each symbol binding existed within a virtual
machine. The readResolve method would be implemented to determine if
that symbol was already defined and substitute the preexisting
equivalent Symbol object to maintain the identity constraint. In this
way the uniqueness of Symbol objects can be maintained across
serialization.
And:
A writeObject method to control what information is saved ...
A readObject method [..] to read the information written ...
A writeReplace method to allow a class to nominate a replacement object to be written to the stream
A readResolve method to allow a class to designate a replacement object for the object just read from the stream
To get full control of Serialization (also to serialize static and transient fields) you have to implement the Externalization interface:
The writeExternal and readExternal methods of the Externalizable
interface are implemented by a class to give the class complete
control over the format and contents of the stream for an object and
its supertypes.
So writeReplace and readResolve methods give you some more control than the ordinary (and automated) serialization mechanism, that is, replace the object before/after serialization. and it is not urgently linked to Singleton serialization, but to fulfill the proxy pattern for serialization. But as you mentioned, this mechanism is also used to implement serialization of a Singleton.

Can a transient variable be serialized in any way?

I faced this question in an interview. Please help me to find the answer. The question was Can a transient variable be serialized in any way?
static and transient fields are not serialized by default.
However they can be serialized if
the same object is accessible via a serialized field.
the object is serialized in a readObject/writeObject or readExternalizable/writeExternalizable.
you are using a different serialization library with different rules (I don't know any which serializes static fields, though I have written such a library by mistake once)
Usually a field is made transient to mean it shouldn't be serialized, though sometimes it might be because
the type is not Serializable
you don't want to use the default Serialization.
Recently in an interview I was also asked this question and here what I answered
Yes, transient member can be serialized. We need to do following to acheive same:
Make your non-serialisable field transient
In writeObject(), first call defaultWriteObject() on the stream to
store all the non-transient fields, then call other methods to
serialize the individual properties of your non-serializable object.
In readObject(), first call defaultReadObject() on the stream to read
back all the non-transient fields, then call other methods
(corresponding to the ones you added to writeObject) to deserialise
your non-serializable object.

How to define an immutable object in a mutable Java class?

In a class, I want to define an empty object and use it anywhere we need it. This object needs to be immutable to avoid accidentally modification. If this object is defined as a public static final member of the class, the object could be changed if the class itself is mutable.
What's the good way to create an immutable object in a mutable class?
If you need to make a class immutable then you need to fulfill this requirements:
all its fields final
the class declared as final
the this reference is not allowed to escape during construction
Any fields which refer to mutable data objects are:
private
have no setter method
they are never directly returned of otherwise exposed to a caller
if they are changed internally in the class this change is not visible and has no effect outside of the class
If you cannot modify the class to make it immutable (final class with final fields, etc.) than just write yourself an immutable wrapper (proxy from GOF?) and use it instead. Inside it can has a delegate to your original class instance.

Why can't we serialize the methods in Java?

Serialization is a mechanism of storing the state of an object. Based on this definition we can say that the instance variables in an object can be serialized.
Methods are behaviors of the class.
We can set and get the state of an object using the methods. So the methods are related to the instance variables of the class.
Then why can't we serialize the methods in Java ?
What do you plan on 'after' serializing the methods? The state of the object has to be by definition should be only its members. Their behaviors would not come into picture. And serialization is saving the state of the object and not its behaviors.
Methods are always serialized: as bytecode in a class file. There is no practical need to serialize them again.
From OOP perspective, the state of an object is the total state of its non-static fields. Methods are a way to define the object behaviour and are common to all instances (objects) of that class, so they are defined as fields at the Class object not as a field of the object (instance) itself. So serializing the object would store its state thus only its fields, but if you serialize the Class object of your objects you would be serializing the methods of those objects (thought I see no reason why would someone bother himself to do so).
Because method the same for all instances of class, they only driven by its data. If you have class definition in your app - you have it's methods.
But data can change from instance to instance.
A method per say does not have any state, and a serialized method call cannot be used for anything. On the other hand, a serialized thread is conceptually a snapshot or checkpoint of a computation, and that would be useful.
However, threads are not serializable in Java, and it would be really difficult to implement this. (For example, how would you cope with the case where the code of one of the active methods was changed between serializing and deserializing a thread?)

Can a transient field in a class be obtained using reflection

Can a transient field in a class be obtained using reflection? (using getDeclaredField(..))
Yes, It is a normal field. You can check whether it is transient by:
Modifier.isTransient(field.getModifiers());
transient:
A keyword in the Java programming language that indicates that a field is not part of the serialized form of an object. When an object is serialized, the values of its transient fields are not included in the serial representation, while the values of its non-transient fields are included.
So no logical reason for it not to be accessible by reflection. It's the value of the field that is ignored (sometimes), not the field itself.
(btw, what hindered you from just trying to call getDeclaredField("yourTransientField")?)
transient indicates that the field will not be serialized. The field is still declared by the class, so it is fair game for reflection.
Among all the objects that needs to be serialized there are those one that need not to be serialized. That's why this objects are marked with the keyword transient.
transient fields have nothing to do with reflection. The keyword only signals that a field should be skipped during Java serialization process. So reflection can access transient fields just like any other fields.

Categories