Reputation: 3134
I have an immutable class with invariant checking. According to Effective Java 2nd Ed item 76 it has a readObjects method that throws an InvalidObjectException if the deserialized object violates the invariants:
// readObject method with validity checking
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
// Check that our invariants are satisfied
if (/* some condition*/)
throw new InvalidObjectException("Invariant violated");
}
I know how to test serialization and deserialization, but this tests only the happy path. There is an ugly way of triggering the InvalidObjectException, where you hardcode a tampered byte stream (shamelessly stolen from EJ2 item 76):
public class BogusPeriod {
// manipulated byte stream
private static final byte[] serializedForm = new byte[] {
(byte)0xac, (byte)0xed, 0x00, 0x05, /* ca. 100 more bytes omitted */ };
// Returns the object with the specified serialized form
private static Object deserializeBogusPeriod() {
try {
InputStream is = new ByteArrayInputStream(serializedForm);
ObjectInputStream ois = new ObjectInputStream(is);
return ois.readObject();
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
}
This is really ugly and will probably break as soon as the serializable class changes. I wonder if there is a simpler method of creating test cases like that? Maybe there is a library that knows at which offsets of a byte stream specific values are located to allow tampering at run time?
Upvotes: 1
Views: 573
Reputation: 996
You assume, that the object/class is deserializable from java (non corrupt data) and want to do some checks afterwards (like if a date in a string is formatted correct).
Writing your unit test for this, you could use a library like Serialysis (https://weblogs.java.net/blog/2007/06/12/disassembling-serialized-java-objects) to check generated byte streams by rightful streamed objects, find out where in the byte stream your data is located and modify your data during test setup.
THOUGH
IF you trust the source of your data you receive and have been able to deserialize, better use some kind of interceptor / validator provided by your framework of choice (Spring in SE, Java EE etc.) at the moment the object reaches your application.
Upvotes: 1