I am investigating different options in the Java Serialization mechanism to allow flexibility in our class structures for version-tolerant storage (and advocating for a diff
I recently faced the same problem, that is, StreamCorruptedException deserializing objects of classes that were moved from one package to another and then evolved in a compatible way by adding new fields. Although @gaponov answer initially solved it, I find the following solution more appropriate because it does not need to mess with the Class name. The class using the ObjectInputStreamAdapter defines the mapping and the internal class ObjectInputStreamAdapter only redefines the resolveClass method:
public class Deserializer {
/*
* Mapping that stores the specific new classes to use for old serialized
* class names in order to transform old classes to the new ones for
* compatibility reasons
*/
private static final Map> classMapping = new HashMap<>();
static {
classMapping.put("com.example.old.SomeClass",
SomeClass.class);
classMapping.put("com.example.old.SomeClass2",
SomeClass2.class);
}
public void deserialize(byte[] bytes) {
try (ObjectInputStream o =
new ObjectInputStreamAdapter(new ByteArrayInputStream(bytes))) {
Object object = o.readObject();
/* ... */
} catch (Exception e) {
throw new SerializationException("Cannot deserialize", e);
}
}
/*
* Adaptor that transform old classes to the new classes for compatibility
* reasons
*/
private class ObjectInputStreamAdapter extends ObjectInputStream {
public ObjectInputStreamAdapter(InputStream in) throws IOException {
super(in);
}
@Override
protected Class> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
Class> klazz = classMapping.get(desc.getName());
if (klazz != null) {
return klazz;
} else {
return super.resolveClass(desc);
}
}
}
}