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

RFE: StackOverflowError decoding XML of immutable class with list member

XMLWordPrintable

    • generic
    • solaris_nevada

      The attached TestListBean.java demonstrates the problem:

      ; javac TestListBean.java
      ; java TestListBean


      The expected result is seen when running on Java 5:

      ; java -version
      java version "1.5.0_11"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_11-b03)
      Java HotSpot(TM) Server VM (build 1.5.0_11-b03, mixed mode)
      ; javac TestListBean.java
      ; java TestListBean
        serialized: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
        deserialized: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
        encoded: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
        decoded: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]


      On Java 6, this fails due to 6505888 'LTP: Java 6 breaks XML encoding/decoding of immutable list member and "id" property':

      ; java -version
      java version "1.6.0-rc"
      Java(TM) SE Runtime Environment (build 1.6.0-rc-b100)
      Java HotSpot(TM) Server VM (build 1.6.0-rc-b100, mixed mode)
      ; javac TestListBean.java
      ; java TestListBean
        serialized: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
        deserialized: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
        encoded: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
      java.lang.InstantiationException: java.util.Collections$UnmodifiableRandomAccessList
      Continuing ...
      java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(TestListBean$Stinky);
      Continuing ...
      Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
              at com.sun.beans.ObjectHandler.dequeueResult(ObjectHandler.java:139)
              at java.beans.XMLDecoder.readObject(XMLDecoder.java:201)
              at TestListBean.performBeanTest(TestListBean.java:98)
              at TestListBean.main(TestListBean.java:286)


      Bug 6505888, targeting 6u2, was fixed in build b01. The above test should work again as expected with that fix. I tested it on 6u2 obtained from

      /net/jano/export/disk29/jcg/NightlyBuilds/update.int/6u2/archived/2007-04-04.6u2

      However, I saw a new problem:

      ; java -version
      java version "1.6.0_02"
      Java(TM) SE Runtime Environment (build 1.6.0_02-b01)
      Java HotSpot(TM) Server VM (build 1.6.0_01-b06, mixed mode)
      ; javac TestListBean.java
      ; java TestListBean
        serialized: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
        deserialized: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
        encoded: TestListBean$Stinky[name = cat, count = 9, tickets = [TestListBean$Ticket[number =1], TestListBean$Ticket[number =2]]]
      Exception in thread "main" java.lang.StackOverflowError
              at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
              at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
              at java.lang.reflect.Method.invoke(Method.java:597)
              at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:243)
              at java.beans.Statement.invoke(Statement.java:214)
              at java.beans.Expression.getValue(Expression.java:98)
              at java.beans.Encoder.getValue(Encoder.java:85)
              at java.beans.Encoder.get(Encoder.java:200)
              at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:94)
      ... repeated many times ...
              at java.beans.Encoder.writeObject(Encoder.java:54)
              at java.beans.XMLEncoder.writeObject(XMLEncoder.java:257)
              at java.beans.Encoder.writeExpression(Encoder.java:279)
              at java.beans.XMLEncoder.writeExpression(XMLEncoder.java:372)
              at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:97)
      ... repeated many times ...


      What's interesting is that the test succeeds if either of the encoded classes overrides equals(). Uncommenting either of the equals() methods in the attached TestListBean.java causes the test to succeed:

              @Override
              public boolean
              equals(Object o)
              {
                  if (o instanceof Ticket) {
                      Ticket t = (Ticket)o;
                      return (number == t.number);
                  }
                  return false;
              }

      or

              @Override
              public boolean
              equals(Object o)
              {
                  if (o instanceof Stinky) {
                      Stinky s = (Stinky)o;
                      return ((name == null ? s.name == null :
                              name.equals(s.name)) &&
                              (count == s.count) &&
                              tickets.equals(s.tickets));
                  }

                  return false;
              }

      Of course it does not make sense for all classes to override equals(), therefore such a hidden requirement is broken (and inconsistent with Java 5).

            Unassigned Unassigned
            teericks Thomas Erickson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: