Bryan Mulvihill
Bryan Mulvihill

Reputation: 63

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?

Upvotes: 6

Views: 429

Answers (3)

DwB
DwB

Reputation: 38300

Implement the readObject and readObjectNoData methods in you class.

Read the appropriate type using ObjectInoutStream.readObject and convert it to the new type

See the Serializable interface API for details.

More Details

You can only fix this easily if you control the source of the class that was serialized into the blob. If you do not control this class, then you have only a few limited and difficult options:

  1. Have the controlling party give you a version of the class that reads the old format and writes the new format.
  2. Write you own form of serialization (as in you read the blob and convert the bytes to classes) that can read the old format and generate new versions of the classes.
  3. Write you own version of the class in question (remove the other from the class path) which reads the old format and produces some intermediate form (perhaps JSON).

Next you have to do one of these

  1. Convince the powers that be that the blob technique is shitty and should be done away with. use the current class change as evidance. Almost any technique is better that this. Writing JSON to the db in the blob is better.
  2. Stop depending on shitty classes from other people. (shitty is a judgement which I can only suspect, not know, is true). Instead create a suite of classes that represent the data in the database and convert from the externally controlled classes to the new data classes before writing to the database.

Upvotes: 0

user207421
user207421

Reputation: 310893

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.

Upvotes: 1

biziclop
biziclop

Reputation: 49744

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.

Upvotes: 2

Related Questions