how to test in Java that a class implements Serializable correctly (not just is an instance of Serializable)
I am implementing a class to be Serializable (so it's a value object for use w/ RMI). But I need to test it. Is there a way to do this easily?
clarification: I'm implementing the class, so it's trivial to stick Serializable in the class definition. I need to manually serialize/deserialize it to see if it works.
I found this C# question, is there a similar answer for Java?
Solution 1:
The easy way is to check that the object is an instance of java.io.Serializable
or java.io.Externalizable
, but that doesn't really prove that the object really is serializable.
The only way to be sure is to try it for real. The simplest test is something like:
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(myObject);
and check it doesn't throw an exception.
Apache Commons Lang provides a rather more brief version:
SerializationUtils.serialize(myObject);
and again, check for the exception.
You can be more rigourous still, and check that it deserializes back into something equal to the original:
Serializable original = ...
Serializable copy = SerializationUtils.clone(original);
assertEquals(original, copy);
and so on.
Solution 2:
utility methods based on skaffman's answer:
private static <T extends Serializable> byte[] pickle(T obj)
throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
private static <T extends Serializable> T unpickle(byte[] b, Class<T> cl)
throws IOException, ClassNotFoundException
{
ByteArrayInputStream bais = new ByteArrayInputStream(b);
ObjectInputStream ois = new ObjectInputStream(bais);
Object o = ois.readObject();
return cl.cast(o);
}
Solution 3:
The short answer is, you can come up with some candidate objects and actually try to serialize them using the mechanism of your choice. The test here is that no errors are encountered during marshalling/unmarshalling, and that the resulting "rehydrated" object is equal to the original.
Alternatively, if you don't have any candidate objects, you could implement a reflection-based test that introspects the (non-static, non-transient) fields of your class to ensure that they too are Serializable. Speaking from experience, this gets surprisingly complex surprisingly quickly, but it can be done to a reasonable extent.
The downside to this latter approach is that if a field is e.g. List<String>
, then you can either fail the class for not having a strictly serializable field, or simply assume that a serializable implementation of List will be used. Neither is perfect. (Mind you, the latter problem exists for examples too; if every example used in the test uses serializable Lists, there's nothing to prevent a non-serializable version being used by some other code in practice).
Solution 4:
This only works for fully populated objects, if you require that any objects composed in your top level object are also serializable then they cannot be null for this test to be valid as serialization/deserialization skips the null objects