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

Cod*_*ind 8 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();
Run Code Online (Sandbox Code Playgroud)

只要toWrite该类实现了Serializable接口,并且所有toWritetransient成员变量也是如此,这将正常工作Serializable.换句话说,您尝试通过toWrite引用发送的整个对象层次结构必须是Serializable.假设这段代码的唯一问题是内部的东西toWrite不是Serializable.

如果层次结构不完整Serializable,则oos.writeObject(toWrite)抛出a 的调用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:###)
Run Code Online (Sandbox Code Playgroud)

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

my.package.MyClass.nonSerializableReference instanceof some.package.and.ClassIDidntExplicitlyReference
Run Code Online (Sandbox Code Playgroud)

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

回答

我最终使用Reflection FieldModifierclass来找到路径.不幸的是,我不能分享我的代码(违反公司政策),但我可以告诉你我的输出.A类持有B的实例,B持有C的实例,C持有D的实例.Serializable除D.之外,我最终使用Depth-First-Search找到路径:

A.b -> 
  B.c -> 
    C.d instanceof class D
Run Code Online (Sandbox Code Playgroud)

如果我做出C.d瞬态,则搜索不会产生任何结果.太酷了!

use*_*256 14

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

  • 这应该是这个问题的首选答案。它立即帮助我解决了这个问题。 (2认同)

dfb*_*dfb 1

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

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