JDK-5023559 : LTP: XMLEncoder emits an extraneous reference to an object with nested targets
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 1.4.2,5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,windows_2000
  • CPU: x86
  • Submitted: 2004-03-30
  • Updated: 2010-07-09
  • Resolved: 2011-03-08
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.
JDK 7
7 b15Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Name: jl125535			Date: 03/30/2004


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

java version "1.4.2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-b28)
Java HotSpot(TM) Client VM (build 1.4.2-b28, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
OS independent

A DESCRIPTION OF THE PROBLEM :
Suppose an object VALUE with a "nontrivial target" (meaning it's instantiate() method returned an Expression describing an instance method on another object) is encountered while the XMLEncoder is attempting to emit XML (i.e., during flush()).  Let the target of VALUE be PARENT.  If PARENT also has a nontrivial target, called GRANDPARENT, and neither GRANDPARENT nor PARENT have been encountered in the emitting process, an extraneous reference to PARENT will be written to the stream.  This is generalizable for as many PARENT objects are "between" VALUE and GRANDPARENT, i.e., if PARENT has a target PARENT1, and PARENT1 has a target PARENT2, ... and PARENTn has the target GRANDPARENT, an extraneous reference will be written for each PARENT, PARENT1...PARENTn.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
javac PT3.java
java PT3

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.2_04" class="java.beans.XMLDecoder">
 <void class="PT3$A">
  <void id="PT3$B0" method="newB">
   <void id="PT3$C0" method="newC"/>
  </void>
 </void>
 <object idref="PT3$C0"/>
</java>

ACTUAL -
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.2_04" class="java.beans.XMLDecoder">
 <void class="PT3$A">
  <void id="PT3$B0" method="newB">
   <void id="PT3$C0" method="newC"/>
  </void>
 </void>
 <object idref="PT3$B0"/>
 <object idref="PT3$C0"/>
</java>

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.beans.*;
import java.io.*;

public class PT3
{
    public static void main(String[] argv)
    {
        XMLEncoder encoder = new XMLEncoder(System.out);
        encoder.setPersistenceDelegate(B.class, new BDelegate());
        encoder.setPersistenceDelegate(C.class, new CDelegate());
        encoder.setExceptionListener(new ExceptionListener()
                                     {
                                         public void
                                         exceptionThrown(Exception e)
                                         {  e.printStackTrace(); }
                                     });
        A a = new A();
        B b = a.newB();
        C c = b.newC();

        encoder.writeObject(c);
        encoder.close();
    }

    public static class A
    {
        public A()
        {}

        public B newB()
        {   return new B(this); }
    }

    public static class B
    {
        private final A m_a;

        public B(A a)
        {   m_a = a; }

        public A getA()
        {   return m_a; }

        public C newC()
        {   return new C(this); }
    }

    public static class C
    {
        private final B m_b;

        public C(B b)
        {   m_b = b; }

        public B getB()
        {   return m_b; }
    }

    public static class BDelegate
        extends DefaultPersistenceDelegate
    {
        protected Expression instantiate(Object p_old, Encoder p_out)
        {
            B b = (B)p_old;
            return new Expression(p_old, b.getA(), "newB", new Object[0]);
        }
    }

    public static class CDelegate
        extends DefaultPersistenceDelegate
    {
        protected Expression instantiate(Object p_old, Encoder p_out)
        {
            C c = (C)p_old;
            return new Expression(p_old, c.getB(), "newC",
                                  new Object[0]);
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Add the following block of code in the else block of the if (target == outer) in outputStatement():

        else {
            d.refs = 2;
            outputValue(target, outer, false);
            // START NEW BLOCK
            if (isArgument) {
                outputValue(value, outer, false);
            }
            // END NEW BLOCK
            // OLD outputValue(value, outer, false);
            return;
        }

and compile the resulting XMLEncoder, put in your bootclasspath.
(Incident Review ID: 245071) 
======================================================================

Comments
EVALUATION I think we should implement the suggested solution.
21-12-2006

SUGGESTED FIX I think we should implement fix suggested by customer. See description. But it should be added together with 5023552.
27-04-2006

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: dragon
14-06-2004

EVALUATION Reproducible as described in 1.4 through 1.5. ###@###.### 2004-03-31 We need to examine the suggested solution, but it looks good. ###@###.### 2005-06-06 15:39:47 GMT
31-03-2004