JDK-5023552 : LTP: XMLEncoder does not update ref count on Statement target in outputStatement()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 1.4.0,1.4.2,1.4.2_01
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • 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 b07Fixed
Related Reports
Duplicate :  
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 :
When emitting statements, the XMLEncoder does not correctly emit an idref for a given object A if A is the target of the Expression to produce B, A is an argument to that Expressiona of, and B is encountered before A.
 a
The problem is in outputStatement(Statement p_stmt, Object outer, boolean isArgument)

There is an if block:

if (outer == target) {
	...
}
else if (...) {
	...
}
else if (...) {
	...
}
else {
	d.refs = 2;
	outputValue(target, outer, false);
	outputValue(value, outer, false);
	return;
}

When emitting the target, it has not seen another reference to target, so the code in outputStatement() that sets ValueData.name in the target's ValueData is not encountered.  Since ValueData.name is never set, it tries to write the Expression for target when writing the arguments for B.  Then, the target is written, but since the value is in the statement list of the target, it writes the value again, which writes the target because target is an argument of the value's Expression, ad infinitum.


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

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

ACTUAL -
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.2_04" class="java.beans.XMLDecoder">
 <void class="PT1$A">
  <void id="PT1$B0" method="newB">
   <object class="PT1$A">
    <void id="PT1$B0" method="newB">
     <object class="PT1$A">
      <void id="PT1$B0" method="newB">
       <object class="PT1$A">
        <void id="PT1$B0" method="newB">
         <object class="PT1$A">
          <void id="PT1$B0" method="newB">
           <object class="PT1$A">
            <void id="PT1$B0" method="newB">
             <object class="PT1$A">
              <void id="PT1$B0" method="newB">
               <object class="PT1$A">
		...
(infinite recursion)

REPRODUCIBILITY :
This bug can be reproduced always.

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

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

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

    public static class A
    {
        public A()
        {}

        public B newB(A a)
        {   return new B(a); }
    }

    public static class B
    {
        private final A m_a;
        public B(A a)
        {   m_a = a; }

        public A getA()
        {   return m_a; }
    }

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

CUSTOMER SUBMITTED WORKAROUND :
If you increment the reference count to target in the else block referred to in the detailed description, as follows:

        else {
            d.refs = 2;
/*NEW*/getValueData(target).refs++;
            outputValue(target, outer, false);
            outputValue(value, outer, false);
            return;
        }

this fixes this problem.
(Incident Review ID: 245032) 
======================================================================

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 5023559.
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 definitely need to fix this recursion in a way like submitter suggests. ###@###.### 2005-06-06 15:30:33 GMT
31-03-2004