3

I have run into an odd situation where, when I successfully serialize a certain object and then deserialize it in another program, I get the following error on deserialization:

Exception in thread "main" java.lang.ClassCastException: cannot assign instance of com.google.common.collect.ImmutableList$SerializedForm to field MyClass.featureExtractors of type com.google.common.collect.ImmutableList in instance of MyClass
        at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2063)
        at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1241)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1970)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
        at my code which calls readObject

The odd thing is that if I add test code to the program which serialized the data to immediately reopen the file and deserialize it, it succeeds with no problems.

Here is the serialization code (and deserialization test) from the writing program:

final FileOutputStream fos = new FileOutputStream(outputModelFile);
final ObjectOutputStream oos = new ObjectOutputStream(new GZIPOutputStream(new BufferedOutputStream(fos)));
oos.writeObject(processedData);
oos.close();

System.out.println("Reloading");
final FileInputStream fin = new FileInputStream(outputModelFile);
final ObjectInputStream ois = new ObjectInputStream(new GZIPInputStream(new    BufferedInputStream(fin)));
final MyClass ret = (MyClass) ois.readObject();
ois.close();

Here is the deserialization code in the reading program:

final FileInputStream fin = new FileInputStream(f);
final ObjectInputStream ois = new ObjectInputStream(new GZIPInputStream(new BufferedInputStream(fin)));

final MyClass ret = (MyClass) ois.readObject();
ois.close();

The structure being serialized and deserialized is extremely complex, with several sub-objects involving custom writeObject/readObjects and readResolves. It seems like if there were an error in a writeObject/readObject pair, it should fail on any attempt to deserialize. A bad readResolve is more plausible, but the only readResolve involved is only doing a form of string interning, and it is not involved with the object throwing the exception. I'm slowly trying to take apart the pieces and test their serialization one-by-one, but I was wondering if anyone had any ideas what could cause this odd behavior?

P.S. A similar exception is discussed in this question, but there it is due to the field in question being involved in a circular reference, which is not happening here.

Update: Of course, ten minutes after I post this, the obvious occurs to me. The two programs are in different Maven modules. The writing program is in the same module as object being written, but the reading program is in another module which depends on the other one. This suggests there is the possibility of some sort of class mismatch.

Community
  • 1
  • 1
Ryan Gabbard
  • 2,269
  • 2
  • 24
  • 37

2 Answers2

1

The writing and reading program were using different versions of Guava and the serialized forms were not compatible between versions. The Guava documentation warns about this, but I had forgotten:

Serialized forms of ALL objects are subject to change. Do not persist these and assume they can be read by a future version of the library.

Ryan Gabbard
  • 2,269
  • 2
  • 24
  • 37
  • That limitation surely have to be problem have to be with the `serialVersionUID`. Take a look at [this article](http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/) – nashuald Nov 15 '13 at 16:26
  • @nashuald: While if one wanted to maintain compatibility between multiple versions of serialized objects, using the `serialVersionUID` would be necessary, I believe the Guava library simply (and reasonably) does not guarantee compatibility of serialized forms between versions at all. – Ryan Gabbard Nov 15 '13 at 17:08
0

Also, sender and receiver sides should better have save Java JVM version. Recently I came up on a case when objects were serialized via Java 1.7, and tried to deserialized via Java 1.6 what threw exact same exception:

java.lang.ClassCastException: cannot assign instance of com.google.common.collect.ImmutableList$SerializedForm to field MyClass.featureExtractors of type com.google.common.collect.ImmutableList in instance of MyClass
Basel Darvish
  • 64
  • 2
  • 11