Unit Testing Serialization Evolution, Take 2
Tom Hawtin suggested that I override
writeClassDescriptor()
instead. It's a good thing because in doing so I realized overridding writeUTF()
as I did in my first try doesn't intercept field types correctly. Enjoy.public static <S> S serializeAndDeserialize(Object o, Class<S> spoofedType) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oout = new SpoofingObjectOutputStream(bout, o.getClass(), spoofedType); oout.writeObject(o); oout.flush(); oout.close(); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream oin = new ObjectInputStream(bin); try { return spoofedType.cast(oin.readObject()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } static class SpoofingObjectOutputStream extends ObjectOutputStream { String oldName; String newName; public SpoofingObjectOutputStream(OutputStream out, Class oldClass, Class newClass) throws IOException { super(out); this.oldName = oldClass.getName(); this.newName = newClass.getName(); } @Override protected void writeClassDescriptor( ObjectStreamClass descriptor) throws IOException { Class clazz = descriptor.forClass(); boolean externalizable = Externalizable.class.isAssignableFrom(clazz); boolean serializable = Serializable.class.isAssignableFrom(clazz); boolean hasWriteObjectData = hasWriteObjectMethod(clazz); boolean isEnum = Enum.class.isAssignableFrom(clazz); writeUTF(replace(descriptor.getName())); writeLong(descriptor.getSerialVersionUID()); byte flags = 0; if (externalizable) { flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; flags |= ObjectStreamConstants.SC_BLOCK_DATA; } else if (serializable) { flags |= ObjectStreamConstants.SC_SERIALIZABLE; } if (hasWriteObjectData) { flags |= ObjectStreamConstants.SC_WRITE_METHOD; } if (isEnum) { flags |= ObjectStreamConstants.SC_ENUM; } writeByte(flags); ObjectStreamField[] fields = descriptor.getFields(); writeShort(fields.length); for (ObjectStreamField field : fields) { writeByte(field.getTypeCode()); writeUTF(field.getName()); if (!field.isPrimitive()) { writeObject(replace(field.getTypeString())); } } } String replace(String className) { if (className.equals(newName)) { throw new RuntimeException( "Found instance of " + className + "." + " Expected instance of " + oldName + "."); } return className.equals(oldName) ? newName : className; } boolean hasWriteObjectMethod(Class clazz) { try { Method method = clazz.getDeclaredMethod("writeObject", ObjectOutputStream.class); int modifiers = method.getModifiers(); return method.getReturnType() == Void.TYPE && !Modifier.isStatic(modifiers) && Modifier.isPrivate(modifiers); } catch (NoSuchMethodException e) { return false; } } }
3 Comments:
What's with the Java? Fun fun! (I'm really anti-java these days)
Shaun
ohpunk.blogspot.com
Sorry. Blogger doesn't support categories or tags. :(
Maybe that's something else FeedBurner could add--tagging.
Hi,
I've used your serialization testing toolkit for a while and it helps me a lot - thank you very much!
But for some weeks I'm going to apply Serialization Proxy pattern (as described in Josh Bloch's Effective Java book). And now your solution breaks.
After fiddling a little bit with the code I think I get a workable solution. Is there any way to post it alongside your solution?
Christian
Post a Comment
<< Home