在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
设为瞬态,则搜索不会产生任何结果。非常酷!
答案 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以获取更多详细信息