Serializing objects to byte arrays – Java I/O: Context-Specific Deserialization Filters
124. Serializing objects to byte arrays
In chapter 4, Problem X, we talked about the serialization/deserialization of Java records, so you should be pretty familiar with these operations. In a nutshell, serialization is the process of transforming an in-memory object into a stream of bytes that can be also stored in memory or written on a file, network, database, external storage, and so on. Deserialization is the reverse process of recreating the object state in memory from the given stream of bytes.A Java object is serializable if its class implements java.io.Serializable (or, java.io.Externalizable). Accomplishing serialization/deserialization takes place via the java.io.ObjectOutputStream and java.io.ObjectInputStream classes and writeObject()/readObject() methods.For instance, let’s assume the following Melon class:
public class Melon implements Serializable {
private final String type;
private final float weight;
// constructor, getters, setters
}
And, an instance of Melon:
Melon melon = new Melon(“Gac”, 2500);
Serializing the melon instance into a byte array can be accomplished as follows:
public static byte[] objectToBytes(Serializable obj)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream ois = new ObjectOutputStream(baos)) {
ois.writeObject(obj);
}
baos.close();
return baos.toByteArray();
}
Of course, we can use this helper to serialize any other object, but for the melon instance we call it as follows:
byte[] melonSer = Converters.objectToBytes(melon);
Deserialization is done via another helper that uses readObject() as follows:
public static Object bytesToObject(byte[] bytes)
throws IOException, ClassNotFoundException {
try ( InputStream is = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(is)) {
return ois.readObject();
}
}
We can use this helper to deserialize any other object from a byte array, but for the melonSer we call it as follows:
Melon melonDeser = (Melon) Converters.bytesToObject(melonSer);
The returned melonDeser restores the initial object state even if it is not the same instance. In the bundled code, you can also see an approach based on Apache Commons Lang.
125. Serializing objects to strings
In the previous problem, you saw how to serialize objects to byte arrays. If we work a little bit on a byte array, we can obtain a string representation of serialization. For instance, we can rely on java.util.Base64 to encode the byte array to String as follows:
public static String objectToString(Serializable obj)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream ois = new ObjectOutputStream(baos)) {
ois.writeObject(obj);
}
baos.close();
return Base64.getEncoder()
.encodeToString(baos.toByteArray());
}
A possible output looks like this:
rO0ABXNyABZtb2Rlcm4uY2hhbGxlbmdlLk1lbG9u2WrnGA2MxZ4CAAJGAAZ3ZWlnaHRMAAR0eXBldAASTGphdmEvbGFuZy9TdHJpbmc7eHBFHEAAdAADR2Fj
String melonSer = Converters.objectToString(melon);
The reverse process relies on Base64 decoder as follows:
public static Object stringToObject(String obj)
throws IOException, ClassNotFoundException {
byte[] data = Base64.getDecoder().decode(obj);
try ( ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data))) {
return ois.readObject();
}
}
Calling this method is straightforward:
Melon melonDeser = (Melon)
Converters.stringToObject(melonSer);
The melonDeser object is the result of deserializing the previous string.