6

ObjectInputStream.readFields() is eligible only within private void readObject(ObjectInputStream) method.

public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException {
  SerialCallbackContext ctx = curContext;
  if (ctx == null) {
    throw new NotActiveException("not in call to readObject");
  }
...

I'm in situation when I can't use default serialisation for reading object (i.e. ObjectInputStream.defaultReadObject()) and don't wish to implement readObject() method in all my classes. In ideal case I would like to have ownDefaultReadObject() method that will construct new object from serialized fields (e.g. by reflection).

Any ideas?

If someone would like to know more. Field names in some of my classes were renamed (e.g. by obfuscator) to a, b, c etc. Such classes were serialized with renamed fields using default Java serialization. I need to deserialise them to original classes (I know pairs of field names for each class; a=> fieldName, b=> age, c=>gender etc.).

FoxyBOA
  • 5,788
  • 8
  • 48
  • 82
  • Your wishes are one thing but what are your *reasons* for not implementing `readObject()`? – user207421 Jul 31 '15 at 09:51
  • I'm not questioning your choice, but wouldn't implementing a `readObject()` that delegates the call to a custom handler be easier? That way, even though you need to implement the method in every class, the implementation would be just a single method call. – biziclop Jul 31 '15 at 09:51
  • @EJP 16: I have several hundreds of such classes. They can be added/removed in a future. I don't wish to anyone in dev. team even think of serialisation/deserializaion issues. One of option that I have to use byte code instrumentation (e.g. Javassist) to add readObject() method during building process, but would like to use simpler solution. – FoxyBOA Jul 31 '15 at 09:55
  • @biziclop: Yes, I'm thinking over this solution, but with byte code instrumentation. Hoping exists an easier one. – FoxyBOA Jul 31 '15 at 09:58
  • @FoxyBOA I would say that there probably isn't an easier solution. But that's just a guess based on the general way serialization seems to work, there may be an unlikely hook you can attach this logic to. – biziclop Jul 31 '15 at 10:03
  • @biziclop: Other (possibly easier) solution could be not use Java serialisation at all for sake of Kryo (https://code.google.com/p/kryo/wiki/V1Benchmarks), XStream (http://x-stream.github.io) or other lightweight serialization library. – FoxyBOA Jul 31 '15 at 10:27
  • @FoxyBOA I thought the premise is that you've already got serialized data that you can't change. ("Such classes were serialized with renamed fields using default Java serialization.") – biziclop Jul 31 '15 at 10:30
  • @biziclop: No, I can choose almost any serialisation engine. We're using db4o right now. Unfortunately the project is dead and I'm investigation for alternative solution. My guess was that native Java serialisation could do what we've for now. I'm stuck with renamed fields. Db4o has even special API for such scenario ... – FoxyBOA Jul 31 '15 at 11:39
  • @FoxyBOA XStream is pretty flexible too in this respect. – biziclop Jul 31 '15 at 11:42
  • How on earth did you get into a situation where you need custom Serialization for hundreds of classes? – user207421 Jul 31 '15 at 12:15
  • @EJP: Long story. We're using serialization (native only other one) for transportation module between production environment and development one. In production our classes are processed (i.e. obfuscated) and in dev. environment we need original one (e.g. for tests). We have complex object hierarchy and only obfuscator knows what (and how) it renames next time. – FoxyBOA Jul 31 '15 at 12:19

1 Answers1

1

To rename fields from an object stream, the method you need to override is ObjectInputStream.readClassDescriptor which returns an ObjectStreamClass.

Instances ObjectStreamClass fulfil one of two different roles through large different subsets of the interface. For the avoidance of doubt, this design choice should not be copied.

  • Describes the fields of a serialisable class running in the current JVM instance. Find these instance through ObjectStreamClass.lookup.
  • Describes the fields of a serialisable class as represented in a particular serialised stream. These instances are returned by the implementations of ObjectInputStream.readClassDescriptor.

In your override call super.readClassDescriptor. This will read in the data from the stream. Substitute the value from the stream with one having the new fields names, if it's a class you're interested in.

How to create you own ObjectStreamClass? Write dummy instance of the classes you are interested in to an ObjectOutputStream. You can do this as part of the built, just keeping the binary data. Read with another ObjectInputStream with readClassDescriptor overridden to stash the descriptors.

ObjectInputStream.defaultReadObject/readFields wouldn't make any sense outside of readObject (or similar) because they rely on the current deserialising object rather than an argument. There are other limitations to prevent other code calling defaultReadObject to rewrite fields that must remain constant, copied validated, security checked or similar.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • I would write some code to do this, but I'm doing other stuff at the moment. Probably a bit late for the original poster and also for Java Serialization. / (I originally posted this answer on the wrong questions, because I am an idiot.) – Tom Hawtin - tackline Jul 15 '19 at 15:55
  • you can use reflection to assign a variable, checkout my solution – Archmede Aug 14 '19 at 03:38