Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I replace Java's default deserialization with my own readObject call?

Someone thought it would be a good idea to store Objects in the database in a blob column using Java's default serialization methods. The structure of these objects is controlled by another group and they changed a field type from BigDecimal to a Long, but the data in our database remains the same. Now we can't read the objects back because it causes ClassCastExceptions.

I tried to override it by writing my own readObject method, but that throws a StreamCorruptedException because what was written by the default writeObject method.

How do I make my readObject call behave like Java's default one? Is there a certain number of bytes I can skip to get to my data?

like image 631
Bryan Mulvihill Avatar asked Oct 08 '14 15:10

Bryan Mulvihill


People also ask

How can you customize serialization process?

Customized serialization can be implemented using the following two methods: private void writeObject(ObjectOutputStream oos) throws Exception: This method will be executed automatically by the jvm(also known as Callback Methods) at the time of serialization.

How do you create a custom serialization in Java?

To customize serialization and deserialization, define readObject() and writeObject() methods in this class. Inside writeObject() method, write class attributes using writeXXX methods provided by ObjectOutputStream . Inside readObject() method, read class attributes using readXXX methods provided by ObjectInputStream .

Does Java deserialization call constructor?

When we de-serialize an object, the constructor of its class is never called. Consider the following example, here we have a class named student with two instance variables and a default constructor (initializing with two hardcoded values) and a parameterized constructor.

Why do we need serialization and deserialization?

Serialization and deserialization work together to transform/recreate data objects to/from a portable format. Serialization enables us to save the state of an object and recreate the object in a new location. Serialization encompasses both the storage of the object and exchange of data.


2 Answers

Externalizable allows you to take full control of serialization/deserialization. But it means you're responsible for writing and reading every field,

When it gets difficult though is when something was written out using the default serialization and you want to read it via Externalizable. (Or rather, it's impossible. If you try to read an object serialized with the default method using Externalizable, it'll just throw an exception.)

If you've got absolutely no control on the output, your only option is to keep two versions of the class: use the default deserialization of the old version, then convert to the new. The upside of this solution is that it keeps the "dirty" code in one place, separate from your nice and clean objects.

Again, unless you want to do things really complicated, your best option is to keep the old class as the "transport" bean and rename the class your code really uses to something else.

like image 162
biziclop Avatar answered Oct 06 '22 15:10

biziclop


If you want to read what's already in your database your only option is to get them to change the class back again, and to institute some awareness that you're relying on the class definition as it was when the class was serialized. Merely implementing your own readObject() call can't fix this, and if the class is under someone else's control you can't do that anyway.

If you're prepared to throw away the existing data you have many other choices starting with custom Serialization, writeReplace()/readResolve(), Externalizable, ... or a different mechanism such as XML.

But if you're going to have third parties changing things whenever they feel like it you're always going to have problems of one kind or another.

BigDecimal to Long sounds like a retrograde step anyway.

like image 22
user207421 Avatar answered Oct 06 '22 13:10

user207421