8

在 Java 中,序列化使读取和写入对象到流非常容易。例如,以下代码片段几乎就是将对象写入流所需的全部内容:

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接口,并且 的所有toWritetransient成员变量也是,这将工作得很好Serializable。换句话说,您尝试通过toWrite引用发送的整个对象层次结构必须是Serializable. 假设这段代码的唯一问题是里面toWrite的东西不是Serializable.

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

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有一个名为的成员 Object 引用nonSerializableReference,该引用已设置为 的实例ClassIDidntExplicitlyReference,而不是Serializable。我希望看到类似下面的打印出来:

my.package.MyClass.nonSerializableReference instanceof some.package.and.ClassIDidntExplicitlyReference

我知道这个问题可能没有快速解决方案,并且可能涉及使用反射。以前这里有没有人这样做过,如果是这样,你介意分享你的见解吗?

回答

我最终使用反射FieldModifier类来找到路径。不幸的是,我无法分享我的代码(违反公司政策),但我可以向您展示我的输出。A 类持有 B 的实例,B 持有 C 的实例,C 持有 D 的实例。Serializable除了 D 之外,我最终使用 Depth-First-Search 来查找路径:

A.b -> 
  B.c -> 
    C.d instanceof class D

如果我做C.d瞬态,搜索不会产生任何结果。很酷!

4

3 回答 3

17

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

于 2016-12-07T03:17:27.687 回答
3

我有同样的问题,我也实现了你所说的爬虫。如果有人仍然对它感兴趣,我在这里展示了代码:A good way to find unserializable fields in Java

于 2014-08-01T21:43:27.393 回答
1

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

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

于 2012-12-06T00:40:57.023 回答