Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6208166

Deserialization fails with cyclic object graph using HashSet

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • 1.4.2
    • core-libs

      FULL PRODUCT VERSION :
      java version "1.4.2_04"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_04-b05)
      Java HotSpot(TM) Client VM (build 1.4.2_04-b05, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows 2000 [Version 5.00.2195]

      A DESCRIPTION OF THE PROBLEM :
      De-serializing an instance of this class throws a NullPointerException:

          import java.io.*;
          import java.util.*;

          private class MyClass implements Serializable
          {
              private String m_name = "anything";
              private Set m_set = new HashSet ();

              public MyClass ()
              {
                  m_set.add (this);
              }

              public int hashCode ()
              {
                  return m_name.hashCode ();
              }
          }

      I think this happens because the VM attempts to de-serialize m_set first and in doing so calls hashCode() on each of its members. However, the instance of MyClass, contained in m_set, has not yet been fully de-serialized since this involves de-serializing m_set first. Thus, m_name is still null when hashCode() is called, causing the Exception.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Serialize and then De-serialize an instance of MyClass using the program provided.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I was expecting to see MyClass De-serialize completely and wihout error.
      ACTUAL -
      A NullPointerException was thrown from the line:

                 return m_name.hashCode ();

      m_name was null.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      java.lang.NullPointerException
      at com.bentley.test.MyClass.hashCode(TestSerialization.java:67)
      at java.util.HashMap.hash(HashMap.java:261)
      at java.util.HashMap.put(HashMap.java:379)
      at java.util.HashSet.readObject(HashSet.java:277)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:324)
      at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:838)
      at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1746)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1274)
      at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1845)
      at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1769)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1274)
      at java.io.ObjectInputStream.readObject(ObjectInputStream.java:324)
      at com.bentley.test.TestSerialization.input(TestSerialization.java:46)
      at com.bentley.test.TestSerialization.main(TestSerialization.java:23)
      Exception in thread "main"

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      /*--------------------------------------------------------------------------------------+
       |
       | $RCSfile: TestSerialization.java,v $
       | $Revision: 1.0 $
       | $Date: 2004/08/24 14:31:30 $
       |
       | $Copyright: (c) 2004 Bentley Systems, Incorporated. All rights reserved. $
       |
       +--------------------------------------------------------------------------------------*/

      package com.bentley.test;

      import java.io.*;
      import java.util.*;


      public class TestSerialization
      {
          public static void main (String[] args) throws Exception
          {
              MyClass obj = new MyClass ();
              byte[] serialized = output (obj);
              Serializable deserialized = input (serialized);
          }

          public static byte[] output (Serializable obj) throws Exception
          {
              ByteArrayOutputStream obytes = new ByteArrayOutputStream ();
              ObjectOutputStream ostream = new ObjectOutputStream (obytes);

              ostream.writeObject (obj);
              ostream.flush ();
              byte[] bytes = obytes.toByteArray ();

              obytes.close ();
              ostream.close ();

              return bytes;
          }

          public static Serializable input (byte[] bytes) throws Exception
          {
              ByteArrayInputStream ibytes = new ByteArrayInputStream (bytes);
              ObjectInputStream istream = new ObjectInputStream (ibytes);

              Serializable obj = (Serializable)istream.readObject ();

              ibytes.close ();
              istream.close ();

              return obj;
          }
      }

      class MyClass implements Serializable
      {
          private String m_name = "anything";
          private Set m_set = new HashSet ();

          public MyClass ()
          {
              m_set.add (this);
          }

          public int hashCode ()
          {
              return m_name.hashCode ();
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I have not found a good one yet, other than to avoid overriding the hashCode method.
      ###@###.### 2004-12-14 10:26:52 GMT

            smarks Stuart Marks
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: