Serialization was intended as a utility within the Java language, which allows objects to be converted into bytes (serialized), send to another endpoint, and reconstructed as an object again (deserialized). This is necessary since java objects only exists within the JVM and can therefore not be send directly.
However, this technique opened opportunities for unwanted guest in the systems. Deserialization could happen on any type of byte input. This meant that outsiders thereby had a way of sending bytes towards an endpoint and affect the system.
For these reasons, it is highly recommended to utilize other alternatives to java’s serialization. One of these alternatives is for example the well-known JSON.
When implementing serializable on a class, three main concerns needs to be considered:
Instead of using java’s default serialization, it will be recommendable, and perhaps even required when the class includes non-primitive fields, to use the custom serialization methods.
This is done by overriding the readObject and writeObject methods, and through the implementation explain how to open and close the object’s non-primitive fields.
Similar to item 50, if you want to keep the advantages of an immutable object when implementing Serializable, it is required to make defensive copies of any none-primitive field.
This is because the readObject-method should be viewed as an alternative to a normal constructor of the object.
Date dateTwo = new Date(dateOne.getTime());
Any singleton class which implements the serializable interface, can no longer be a singleton. This is because of the readObject() method, which is automatically implemented to deserialize the object and create a new instance.
In order to make the class remain a singleton, it is necessary to implement the readResolve() method, which is automatically called directly after readObject().
Within the readResolve() method, the object is then to return the intended singleton instance of the class instead of the new deserialized object. For this scenario, it would be recommended to return the object as an enum instance.
Implementing Serializable on any class, introduces the risk of bugs and errors associated with serializing and deserializing.
To avoid or limit this risk, it is recommendable to use the serialization proxy pattern.
The pattern evolves around having a copy of the concrete class (aka. proxy), which replaces it through the writeReplace() method.
Within the proxy the constructor takes in an instance of the concrete class as its only argument and assign it to its fields.
Then the proxy overrides the readResolve() and returns an instance of the concrete class.
Finally, the concrete class overrides its own readObject() method and implements a thrown exception to ensure that it is never called directly, but only through the proxy.
My name is Daniel H. Jacobsen and I’m a dedicated and highly motivated software developer with a masters engineering degree within the field of ICT.
I have through many years of constantly learning and adapting to new challenges, gained a well-rounded understanding of what it takes to stay up to date with new technologies, tools and utilities.
The purpose of this blog is to share both my learnings and knowledge with other likeminded developers as well as illustrating how these topics can be taught in a different and alternative manner.
If you like the idea of that, I would encourage you to sign up for the newsletter.