查找违反非Serializable成员变量的路径

时间:2012-12-05 23:31:15

标签: java serialization

在Java中,Serialization使得对象的读取和写入非常容易。例如,以下代码片段主要用于将对象写入流:

ObjectOutputStream oos = ... //Initialize your output stream
Object toWrite = ...         //Initialize what you want to write here
oos.writeObject(toWrite);    //Writes the object to the stream
oos.flush();

如果toWrite的类实现Serializable接口,并且所有toWrite的非transient成员变量也是如此,这将正常工作Serializable。换句话说,您尝试通过toWrite引用发送的整个对象层次结构必须为Serializable。假设此代码的唯一问题是toWrite内的某些内容不是Serializable

如果层次结构不完全Serializable,则对oos.writeObject(toWrite)的调用将引发java.io.NotSerializableException。这一切都很好,除了Exception没有为您提供快速解决问题所需的一切。它会告诉你哪个类无法序列化。您的堆栈跟踪可能如下所示:

java.io.NotSerializableException: some.package.and.ClassIDidntExplicitlyReference
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    ...
    at my.package.MyClass.codeThatWroteTheOffendingObject(MyClass.java:###)

这种方式指向正确的方向,但在涉及toWrite引用的深层对象层次结构的情况下,并不总是清楚违规类引用的来源。假设我将toWrite分配给MyClass的实例,我的MyClass实例有一个名为nonSerializableReference的成员对象引用,该引用已设置为{{1}的实例},这不是ClassIDidntExplicitlyReference。我希望看到以下内容打印出来:

Serializable

我知道这个问题可能没有快速解决方案,可能会涉及使用Reflections。有没有人在这里做过这件事,如果有的话,你介意分享你的见解吗?

答案

我最终使用Reflection的my.package.MyClass.nonSerializableReference instanceof some.package.and.ClassIDidntExplicitlyReference Field类来查找路径。不幸的是,我不能分享我的代码(违反公司政策),但我可以告诉你我的输出。 A类持有B的实例,B持有C的实例,C持有D的实例。除了D之外,所有都是Modifier。我最终使用Depth-First-Search找到路径:

Serializable

如果我将A.b -> B.c -> C.d instanceof class D 设为瞬态,则搜索不会产生任何结果。非常酷!

3 个答案:

答案 0 :(得分:13)

将标志-Dsun.io.serialization.extendedDebugInfo=true传递给JVM,它会在您抛出NotSerializableException时为您提供所需的确切信息。

答案 1 :(得分:3)

我遇到了同样的问题,我也实现了你谈到的抓取工具。如果有人仍然对它感兴趣,我在这里提出了代码:A good way to find unserializable fields in Java

答案 2 :(得分:1)

这是一个奇怪的问题 - 您希望在运行时确定在编译时应该做什么。理论上,对象的路径不应该重要 - 您需要找到引用不可序列化的东西来修复代码的对象。

也就是说,您可以使用反射编写一个简单的递归树爬虫。也就是说,您可以通过实现自己的ObjectInputStream来实现,该ObjectInputStream可以正确记录对象。我建议您查看source以获取更多详细信息