This discussion is archived
7 Replies Latest reply: Mar 5, 2012 4:17 PM by EJP RSS

Custom Deserialization for a List of serializable objects

843790 Newbie
Currently Being Moderated
I'm running into trouble creating custom deserialization using the readObject method.

Here is the code the reads the blob from the database:
Blob blob = rs.getBlob(idx++);
            InputStream iStream = blob.getBinaryStream();
            try {
                ObjectInputStream oiStream = new ObjectInputStream(iStream);
                Object object = oiStream.readObject();
                List data = (List) object;
                report.setData(data);
            }
            catch (EOFException ignored) {}
            finally {
                iStream.close();                
            }
And my class:
public class PerformanceReportRowInfo extends PerformanceInfo
{
    private static final long serialVersionUID = 20060406L;
    
    private String _dateStr;
    private long _queries;
    
    private void readObject (ObjectInputStream ois) throws IOException,
            ClassNotFoundException
    {
        ObjectInputStream.GetField fields = ois.readFields();
        _dateStr = (String) fields.get("_dateStr", null);
        try {
            _queries = fields.get("_queries", 0L);
        } catch (IOException io) {
            int intQueries = fields.get("_queries", 0);
            _queries = (long) intQueries;
        }
    } 
}
The reason custom deserialization is needed is because we are converting the "_queries" attribute from an int to a long, and do not want to have to replace all the blobs in our DB with long types.

For some reason, however, the readObject method never gets called in the PerformanceReportRowInfo, and instead i continue to get the error message:

java.io.InvalidClassException: PerformanceReportRowInfo; incompatible types for field _queries

I even added logging to the readObject method to make sure it wasnt getting called, and my suspicion was confirmed, it was indeed not getting called. Is my problem related to the fact that it is extending another serializable object (in this case PerformanceInfo) that doesnt have a custom readObject method? Or is it because of how im converting the blob to a List in the first block of code? BTW, the exception occurs at this line:

Object object = oiStream.readObject();

Thanks for the help!
  • 1. Re: Custom Deserialization for a List of serializable objects
    EJP Guru
    Currently Being Moderated
    Looks OK, the signature is correct, and none of the reasons you've advanced would explain why it isn't being called. I would check your deployment - is this version of the class really there when you execute?
  • 2. Re: Custom Deserialization for a List of serializable objects
    843790 Newbie
    Currently Being Moderated
    yes it is the code that my deployment is running, if i change the queries object back into an "int", things work fine (readObject still not called), but when i change it to long, i get the exception.
  • 3. Re: Custom Deserialization for a List of serializable objects
    jtahlborn Expert
    Currently Being Moderated
    is your PerformanceInfo class Serializable or Externalizable?

    also, can you post the full stack trace of the exception you are getting?

    Edited by: jtahlborn on May 9, 2008 10:55 AM
  • 4. Re: Custom Deserialization for a List of serializable objects
    843790 Newbie
    Currently Being Moderated
    It is Serializable and does not extend any other class (except Object of course), here is the full stack trace:

    Caused by: java.io.InvalidClassException: PerformanceReportRowInfo; incompatible types for field _queries
         at java.io.ObjectStreamClass.matchFields(ObjectStreamClass.java:2175)
         at java.io.ObjectStreamClass.getReflector(ObjectStreamClass.java:2070)
         at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:586)
         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
         at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1699)
         at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
         at java.util.ArrayList.readObject(ArrayList.java:591)
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
         at java.lang.reflect.Method.invoke(Method.java:585)
         at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:946)
         at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1809)
         at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719)
         at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
         at MyClass.readReport(MyClass.java:332)
  • 5. Re: Custom Deserialization for a List of serializable objects
    EJP Guru
    Currently Being Moderated
    I can't explain why your readObject() method isn't being called unless it is a deployment issue, but I would suggest you use a technique that's better anyway.

    Instead of changing the type, you leave it alone and add another field of type 'long'. Serialization can handle that without any difficulty. Then you just have to adjust the logic in your class to return the long field instead of the int field if it is non-zero. Keep the serialVersionUID the same.

    You should follow this strategy for all serializable classes.

    For general information about stream compatibility under serialization see the Versioning section in the Serialization Specification.
  • 6. Re: Custom Deserialization for a List of serializable objects
    921887 Newbie
    Currently Being Moderated
    I know this thread has been dead a while but I have run into the same issue. I changed a field on the object being serialized from int to float. All that were serialized failed to deserialize of course. But, newly serialized objects were fine and they did go into the readObject method that was create with the new version of the object (same serialVersionId). So the old objects did not have a readObject() method when serialized but the new ones did. The old objects would never go in the readObject() method but the new ones did. This was very unexpected. It was not a Class Loader issue. It seems the objects are marked in some way so the JVM knows who has a readObject method when serialized and who does not, perhaps as a performance enhancement. Still researching to see if this is the case or not.

    Jim
  • 7. Re: Custom Deserialization for a List of serializable objects
    EJP Guru
    Currently Being Moderated
    Review your observations. The readObject() method is called if it is defined in the class that is loaded when the deserialization occurs, period. It has nothing to do with what is in the stream, unless maybe the serialized object was originally Externalizable.