Customize serialization in Java
How do I create my own serialization protocol?
To create your own serialization protocol, it is enough to implement the Externalizable interface, which contains two methods:
public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
serialVersionUID field in serialization
serialVersionUID is used to indicate the version of the serialized data.
When we don't explicitly declare the serialVersionUID in our class, the Java runtime does it for us, but the process is sensitive to many of the class's metadata, including the number of fields, the type of the fields, the access modifiers of the fields, the interfaces that the class implements, etc.
It is recommended to explicitly declare serialVersionUID since when adding or removing class attributes, the dynamically generated value may change and an InvalidClassException will be thrown at the time of execution.
private static final long serialVersionUID = 20161013L;
The serialVersionUID must be changed when an incompatible change is made to the class, for example when an attribute is removed.
Problem with serializing Singleton
The problem is that after deserialization we will get another object. Thus, serialization makes it possible to create the Singleton again, which is not valid. There are two ways to avoid this:
- explicit denial of serialization
- defining a method with signature (default/public/private/protected/) Object readResolve() throws ObjectStreamException, whose purpose is to return a replacement object instead of the object on which it was called.
Ways to control the values of a deserialized object
If you need to control the values of the deserialized object, you can use the ObjectInputValidation interface with overriding the validateObject() method.
// If you call the validateObject() method after deserializing the object,
// an InvalidObjectException exception will be thrown
// if the age value is outside 39 ... 60.
public class Person implements java.io.Serializable,
java.io.ObjectInputValidation {
...
@Override
public void validateObject() throws InvalidObjectException {
if ((age < 39) || (age > 60))
throw new InvalidObjectException("Invalid age");
}
}
There are also ways of signing and encryption to make sure that the data has not been changed:
- using the description of the logic in writeObject() and readObject()
- put in the wrapper class javax.crypto.SealedObject and/or java.security.SignedObject. These classes are serializable, so when you wrap an object in a SealedObject, a kind of "gift wrapping" is created around the original object. For encryption, a symmetric key must be created, which must be managed separately. Likewise, you can use the SignedObject class to validate data, which also requires a separately managed symmetric key.
Read also:
Comments
Post a Comment