JDK-6542811 : RFE: StackOverflowError decoding XML of immutable class with list member
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 6u2
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: solaris_nevada
  • CPU: generic
  • Submitted: 2007-04-05
  • Updated: 2021-07-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Description
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).

Comments
- this is an issue reported against 7(7u), - there are now affected version 9 filed for this issue - 7u issues are transferred to Sustaining Nevertheless if someone have a report against 9 - please reopen and add affectedVersion 9 or 7u specific escalations might be reopen to Sustaining
10-08-2014

- this is an issue reported against 7(7u), - there are now affected version 9 filed for this issue - 7u issues are transferred to Sustaining Nevertheless if someone have a report against 9 - please reopen and add affectedVersion 9 or 7u specific escalations might be reopen to Sustaining
10-08-2014

These are all approved for deferral to JDK 9 so you can update the FixVersion to state JDK 9. Kind regards, Mathias
29-08-2013

These are all approved for deferral to JDK 9 so you can update the FixVersion to state JDK 9. Kind regards, Mathias
29-08-2013

These are all approved for deferral to JDK 9 so you can update the FixVersion to state JDK 9. Kind regards, Mathias
29-08-2013

Converted "8-client-defer-candidate" label to "8-defer-request" by SQE' OK.
15-08-2013

*This is anti-deferral criteria list*: - P2 -------------- Engineering's Criteria ------------------------------------- - tck-red labeled - conformance labeled - P3 regressions reported/labeled against jdk8 - findbugs, parfait, eht labeled bugs - CAP <1 year reported - netbeans <1 year reported Victor ----------------- SQE's OK --------------------------------- Yes, we are ok with that thanks, Mikhail
15-08-2013

EVALUATION The XMLEncoder assumes that the value of the property is equal to original value. I mean if you set some value with the setter (or constructor) you should get it with the getter. In this case we get a defensive copy of the object. So we should find the way to process such case correctly. I think it requires a lot of changes in XMLEncoder, so it is not a bug but RFE.
17-04-2007