【问题标题】:Serialize cyclic object tree – StackOverflowError – custom serialization code needed序列化循环对象树 – StackOverflowError – 需要自定义序列化代码
【发布时间】:2023-03-23 00:36:01
【问题描述】:

我正在制作一个 android 应用程序,其中我有一个 需要序列化的双向循环对象树 以填充 Sqlite 数据库中的 blob 字段。 但是默认的序列化实现会向我抛出 StackOverflowError (底部的堆栈跟踪)。但是我没有编写自定义 java 序列化代码来避免这种情况的经验。

我这个线程(StackOverflowError when serializing an object in Java)他谈到了这个问题,但在我的情况下如何实现它我真的不知道:

可以为这样的列表类定义 writeObject() 方法 即,当第一个链接被序列化时,只需遍历列表并 迭代地序列化每个链接;这将阻止默认 使用递归机制。

这是我的对象模型(看 1/M,而不是其他标志):

这是我用来将对象模型序列化为字节数组的方法(本来不那么重要):

public byte[] serialize(Object object) {
        byte[] buf = null;
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutput out = new ObjectOutputStream(bos);
            out.writeObject(object);
            out.close();
            buf = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buf;
    }

自定义序列化函数:

private void writeObject(java.io.ObjectOutputStream out) throws IOException {
    //please help me with this code
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
    //please help me with this code
}

希望有人帮我解决这个问题。任何线索表示赞赏。

异常堆栈跟踪:

05-25 20:28:16.231: E/AndroidRuntime(14451): FATAL EXCEPTION: main
05-25 20:28:16.231: E/AndroidRuntime(14451): java.lang.StackOverflowError
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.util.IdentityHashMap.findIndex(IdentityHashMap.java:419)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.util.IdentityHashMap.get(IdentityHashMap.java:371)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.dumpCycle(ObjectOutputStream.java:471)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1739)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.util.ArrayList.writeObject(ArrayList.java:651)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.lang.reflect.Method.invokeNative(Native Method)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.lang.reflect.Method.invoke(Method.java:507)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1219)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.util.ArrayList.writeObject(ArrayList.java:651)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.lang.reflect.Method.invokeNative(Native Method)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.lang.reflect.Method.invoke(Method.java:507)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1219)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
05-25 20:28:16.231: E/AndroidRuntime(14451):    at java.io.ObjectOutputStream.writeObject

【问题讨论】:

  • 每个序列化的 blob 中有多少回合、玩家、玩家和席位?我对正在发生的事情有一个想法,但想用数字来验证它:)
  • 回合数:x,玩家数:4-7,出场数:x*玩家数,座位数:4-7。每件事都在一个 blob 中 - 序列化游戏对象。
  • x 是几十、几百、几千:D
  • 这些对于典型的 JVM 来说并不是很大的数字,但实际上它取决于堆栈大小,我想这在 android 设备上是相当有限的。

标签: java android serialization deserialization cyclic


【解决方案1】:

Java 序列化可以正确处理循环图,但是长列表是个问题。

如果我理解正确,您的问题与您链接的文章中的问题有点不同,因为该文章讨论了没有正确 writeObject 的链表 .. 而目前您正在使用 ArrayLists,它已经将对象存储为平面数组,并且还有一个合适的 writeObject。

但是,如果我做对了,发生的事情或多或少是这样的:

你开始序列化对象 A,在序列化过程中它遇到一个长列表,获取第一个元素并序列化对象 B,对象 B 也有一个长列表,它获取第一个元素,再次说它是 A,因为它已经被序列化它会跳过 A,因此它不会以无限循环结束,而是转到 B 列表中的第二个对象,即 C,C 也有一个长列表,前两个元素再次是 A 和 B ,所以它们被跳过了,第三个是 D,它也有一个列表....等等。

由于这些步骤中的每一步都是堆栈空间中的几行,因此它会被填满,即使它们都是具有适当 writeObject 方法的 ArrayList。

与您拥有的运行时相比,如果这些列表扩展为相对“大”的数字,则可能会出现这种情况。这就是我在评论中问的原因。也许可以找到一种解决方案,避免序列化某些列表(使它们成为瞬态),并在“部分”反序列化后重建它们。

【讨论】:

  • 我认为你是对的.. 但我真的不知道如何重建列表。你会怎么做?
  • 我设法像你说的那样解决了它——谢谢。我从 Player 瞬态创建了播放列表并创建了一个enrichModel 函数并在反序列化模型后调用它:for (Round round : game.Rounds) { for (Played played : round.Playeds) { played.Player.Playeds.add(played); } }
猜你喜欢
  • 2010-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-24
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
相关资源
最近更新 更多