如何在Java中testing一个类正确地实现了Serializable(不仅仅是一个Serializable的实例)
我正在实现一个类是可序列化的(所以它是一个价值对象使用w / RMI)。 但是我需要testing它。 有没有办法很容易做到这一点?
澄清 :我正在实现这个类,所以在类定义中使用Serializable是很简单的。 我需要手动序列化/反序列化,看看它是否工作。
我发现这个C#的问题 ,有没有类似的Java答案?
简单的方法是检查对象是java.io.Serializable
还是java.io.Externalizable
的实例,但这并不能真正certificate对象是可序列化的。
唯一可以肯定的就是尝试一下。 最简单的testing是这样的:
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(myObject);
并检查它不会抛出exception。
Apache Commons Lang提供了一个相当简单的版本:
SerializationUtils.serialize(myObject);
再次检查exception。
你仍然可以更加严格,并检查它是否反序列化为原来的东西:
Serializable original = ... Serializable copy = SerializationUtils.clone(original); assertEquals(original, copy);
等等。
基于skaffman的回答的效用方法:
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); }
这个代码应该这样做…
import java.io.ByteArrayOutputStream; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; public class Main { public static void main(String[] args) { System.out.println(isSerializable("Hello")); System.out.println(isSerializable(new Main())); } public static boolean isSerializable(final Object o) { final boolean retVal; if(implementsInterface(o)) { retVal = attemptToSerialize(o); } else { retVal = false; } return (retVal); } private static boolean implementsInterface(final Object o) { final boolean retVal; retVal = ((o instanceof Serializable) || (o instanceof Externalizable)); return (retVal); } private static boolean attemptToSerialize(final Object o) { final OutputStream sink; ObjectOutputStream stream; stream = null; try { sink = new ByteArrayOutputStream(); stream = new ObjectOutputStream(sink); stream.writeObject(o); // could also re-serilalize at this point too } catch(final IOException ex) { return (false); } finally { if(stream != null) { try { stream.close(); } catch(final IOException ex) { // should not be able to happen } } } return (true); } }
简而言之,您可以想出一些候选对象,并尝试使用您select的机制来序列化它们。 这里的testing是在编组/解组过程中不会遇到任何错误,并且生成的“再水合”对象与原始对象相同。
另外,如果你没有任何候选对象,你可以实现一个基于reflection的testing来反省你的类的(非静态的,非暂态的)字段,以确保它们也是可序列化的。 从经验上讲,这个令人惊讶的复杂得惊人的迅速,但它可以做到一个合理的程度。
后一种方法的缺点是,如果一个字段是例如List<String>
,那么你可能因为没有一个严格的可序列化字段而导致该类失败,或者简单地假定将使用List的可序列化实现。 两者都不是完美的。 (注意,后面的问题也存在于示例中;如果testing中使用的每个示例都使用可序列化的列表,则实际上没有什么能够阻止其他代码使用不可序列化的版本)。
你可以做以下testing:
- 序列化对象到文件并确保没有抛出exception。
- 另外,将对象反序列化并与原始对象进行比较。
下面是序列化和反序列化对象到文件的示例:
这只适用于完全填充的对象,如果您要求在顶级对象中构成的任何对象也是可序列化的,那么它们不能为null,因为这个testing是有效的,因为序列化/反序列化跳过空对象