Java Custom Serialization

JavaSerialization

Java Problem Overview


I have an object that contains a few unserializable fields that I want to serialize. They are from a separate API that I cannot change, so making them Serializable is not an option. The main problem is the Location class. It contains four things that can be serialized that I'd need, all ints. How can I use read/writeObject to create a custom serialization method that can do something like this:

// writeObject:
List<Integer> loc = new ArrayList<Integer>();
loc.add(location.x);
loc.add(location.y);
loc.add(location.z);
loc.add(location.uid);
// ... serialization code

// readObject:
List<Integer> loc = deserialize(); // Replace with real deserialization
location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3));
// ... more code

How can I do this?

Java Solutions


Solution 1 - Java

Java supports Custom Serialization. Read the section Customize the Default Protocol.

To quote:

> There is, however, a strange yet crafty solution. By using a built-in > feature of the serialization mechanism, developers can enhance the > normal process by providing two methods inside their class files. > Those methods are:

    >
  • private void writeObject(ObjectOutputStream out) throws > IOException; >
  • private void readObject(ObjectInputStream in) throws > IOException, ClassNotFoundException;

In this method, what you could do is serialize it into other forms if you need to such as the ArrayList for Location that you illustrated or JSON or other data format/method and reconstruct it back on readObject()

With your example, you add the following code:




private void writeObject(ObjectOutputStream oos)
throws IOException {
// default serialization
oos.defaultWriteObject();
// write the object
List loc = new ArrayList();
loc.add(location.x);
loc.add(location.y);
loc.add(location.z);
loc.add(location.uid);
oos.writeObject(loc);
}




private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException {
// default deserialization
ois.defaultReadObject();
List loc = (List)ois.readObject(); // Replace with real deserialization
location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3));
// ... more code




}


Solution 2 - Java

Similar to @momo's answer but without using a List and auto-boxed int values which will make it much more compact.

private void writeObject(ObjectOutputStream oos) throws IOException {
    // default serialization 
    oos.defaultWriteObject();
    // write the object
    oos.writeInt(location.x);
    oos.writeInt(location.y);
    oos.writeInt(location.z);
    oos.writeInt(location.uid);
}

private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
    // default deserialization
    ois.defaultReadObject();
    location = new Location(ois.readInt(), ois.readInt(), ois.readInt(), ois.readInt());
    // ... more code

}

Solution 3 - Java

If it must be Java serialization, the only way I know of is to redefine the readObject() and writeObject() in all classes having a reference to an instance of Location as shown in Momo's answer. Note that this will not allow you to serialize a Location[], and require you to subclass all Collection<Location> appearing in your code. Moreover, it requires the fields of type Location to be marked transient, which will exclude their definitions from being written to the serialization stream, possible foiling the detection of incompatible class changes.

A better way would be to simply override ObjectOutputStream.writeObject. Alas, that method is final. You could override ObjectOutputStream.writeObjectOverride() instead, but that method can not delegate the default implementation, ObjectOutputStream.writeObject0() because that method is private. Of course, you could invoke the private method using reflection, but ...

Therefore, I recommend verifying your constraints. Does it have to be Java serialization? Can you really not change the definition of class Location?

If you have the source code to class Location, it's quite trivial to add implements Serializable and add it to your classpath. Yes, you'll have to do this again whenever you upgrade the library, but it might be better than the alternative ...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexis KingView Question on Stackoverflow
Solution 1 - JavamomoView Answer on Stackoverflow
Solution 2 - JavaPeter LawreyView Answer on Stackoverflow
Solution 3 - JavameritonView Answer on Stackoverflow