查找违反非Serializable成员变量的路径
在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
引用发送的整个Object层次结构必须是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
的成员Object引用,该引用已设置为ClassIDidntExplicitlyReference
的实例,该实例不是Serializable
。 我希望看到以下内容打印出来:
my.package.MyClass.nonSerializableReference instanceof some.package.and.ClassIDidntExplicitlyReference
我知道这个问题可能没有快速解决方案,并可能涉及使用Reflections。 有没有人在这里做过这件事,如果有的话,你介意分享你的见解吗?
回答
我最终使用Reflection的Field
和Modifier
类来查找路径。 不幸的是,我不能分享我的代码(违反公司政策),但我可以告诉你我的输出。 A类包含B的实例,B包含C的实例,C包含D的实例。除D外,所有都是Serializable
。我最终使用Depth-First-Search查找路径:
Ab -> Bc -> Cd instanceof class D
如果我使Cd
瞬态,搜索不会产生任何结果。 太酷了!
这是一个奇怪的问题 – 您希望在运行时确定在编译时应该做什么。 从理论上讲,对象的路径无关紧要 – 您需要找到引用不可序列化的东西来修复代码的对象。
也就是说,您可以使用reflection编写一个简单的递归树爬虫。 也就是说,您可以通过实现自己的ObjectInputStream来实现,该ObjectInputStream可以正确记录对象。 我建议您查看源代码以获取更多详细信息
将标志-Dsun.io.serialization.extendedDebugInfo=true
传递给JVM,它会在抛出NotSerializableException
时为您提供所需的信息。
我有同样的问题,我也实现了你谈到的爬虫。 如果有人仍对它感兴趣,我在这里展示了代码: 在Java中查找不可序列化字段的好方法