I want to replace the String "com.oldpackage.className" with "com.newPackage.className" in a stream of serialized data. This serialized data is read from the DB and updated after replacing the string.
I am facing some problems while doing the same. If you already guessed it, this is part of a refactoring exercise. Are there any libraries that would help me in manipulating the serialized data? If you can also please comment on any precautions or caveats, it would be of great help.
Thanks a lot, Chris. P.S: Both the old class and the new class do not declare a serialversion ID as part of its fields.
I do not know how to do what your are trying but I can suggest you "legal" solution. Implement convertor that has both old and new packages in classpath and does the following: reads data from DB, de-serializes it using the old package, converts old instances to new in java and then stores new data in DB again.
This solution requires performing some dirty job but it is safe. Moreover the results may be reused in future. But I wish you good luck to find solution that just replaces class name in serialized data.
To precise Tom Hawtin's reply, I have managed to implement it using the following code:
public static ObjectInputStream getSwapOIS( InputStream in ,String fromClass,String toClass)
throws IOException ,ClassNotFoundException {
final String from="^"+fromClass,fromArray="^\\[L"+fromClass,toArray="[L"+toClass;
return new ObjectInputStream(in) {
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException
{
String name = desc.getName().replaceFirst(from, toClass);
name = name.replaceFirst(fromArray, toArray);
return Class.forName(name);
}
protected ObjectStreamClass readClassDescriptor()
throws IOException, ClassNotFoundException
{
ObjectStreamClass cd = super.readClassDescriptor();
String name = cd.getName().replaceFirst(from, toClass);
name = name.replaceFirst(fromArray, toArray);
if(!name.equals(cd.getName())) {
cd = ObjectStreamClass.lookup(Class.forName(name));
}
return cd;
}
};
}
Note that you also need to override readClassDescriptor(). It works for both standard types and arrays and you can even change the class name not just the package name. Just do:
InputStream in = new ByteArrayInputStream(classBytes);
ObjectInputStream ois = getSwapOIS( in,
"com.oldpackage.className",
"com.newpackage.newClassName");
Object myObject= ois.readObject();
IIRC you can (with sufficient permissions) override ObjectInputStream.resolveClass
(and resolveProxyClass
) to return a Class
with a different package names. Although, IIRC, you cannot change the simple class name.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With