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

XMLEncoder never encodes property that is an immutable bean

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • 6
    • client-libs

      FULL PRODUCT VERSION :
      java version "1.6.0"
      Java(TM) SE Runtime Environment (build 1.6.0-b105)
      Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)


      ADDITIONAL OS VERSION INFORMATION :
      Linux itis-asus-desktop 2.6.20-16-generic #2 SMP Thu Jun 7 20:19:32 UTC 2007 i686 GNU/Linux


      A DESCRIPTION OF THE PROBLEM :
      Incorrect XML is produced for a particulary set of beans:
      ParentBean having one property "bean", an ImmutableBean
      ImmutableBean having one property "a", an int. This property is immutable - it is set in the constructor, and has a getter only. A DefaultPersistenceDelegate is registered, and this bean will encode correctly when it is encoded directly rather than as a property of ParentBean.

      When ParentBean has a default constructor giving "bean" property a default value, any instance of ParentBean will be encoded with default "bean" property in the XML. That is, the XML will just create a default ParentBean, regardless of what was encoded.

      If ParentBean gives "bean" property the value null in default constructor, it will be encoded correctly

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the ParentTest class, check output to console and user.dir

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Should serialise with the ImmutableBean encoded, producing the following output:

      ImmutableBean a value, should be 254: 254
      Default parent.getBean().getA() value: 1
      parent.getBean().getA() value after calling parent.setBean(): 47
      parent.getBean().getA() value after XML encoding and decoding: 47

      And the following XML in user directory:

      ParentBean.xml:

      <?xml version="1.0" encoding="UTF-8"?>
      <java version="1.6.0" class="java.beans.XMLDecoder">
       <object class="com.itis.proto.ParentBean">
        <void property="bean">
         <object class="com.itis.proto.ImmutableBean">
          <int>47</int>
         </object>
        </void>
       </object>
      </java>


      ImmutableBean.xml:

      <?xml version="1.0" encoding="UTF-8"?>
      <java version="1.6.0" class="java.beans.XMLDecoder">
       <object class="com.itis.proto.ImmutableBean">
        <int>254</int>
       </object>
      </java>

      ACTUAL -
      Actually serialises with ImmutableBean missing (assumed to be default), producing the following output:

      ImmutableBean a value, should be 254: 254
      Default parent.getBean().getA() value: 1
      parent.getBean().getA() value after calling parent.setBean(): 47
      parent.getBean().getA() value after XML encoding and decoding: 1

      And the following XML in user directory:

      ParentBean.xml:

      <?xml version="1.0" encoding="UTF-8"?>
      <java version="1.6.0" class="java.beans.XMLDecoder">
       <object class="com.itis.proto.ParentBean"/>
      </java>

      ImmutableBean a value, should be 254: 254
      Default parent.getBean().getA() value: 1
      parent.getBean().getA() value after calling parent.setBean(): 47
      parent.getBean().getA() value after XML encoding and decoding: 47

      And the following XML in user directory:

      ParentBean.xml:

      <?xml version="1.0" encoding="UTF-8"?>
      <java version="1.6.0" class="java.beans.XMLDecoder">
       <object class="com.itis.proto.ParentBean">
        <void property="bean">
         <object class="com.itis.proto.ImmutableBean">
          <int>47</int>
         </object>
        </void>
       </object>
      </java>

      ImmutableBean.xml:


      <?xml version="1.0" encoding="UTF-8"?>
      <java version="1.6.0" class="java.beans.XMLDecoder">
       <object class="com.itis.proto.ImmutableBean">
        <int>254</int>
       </object>
      </java>


      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      No exceptions - listeners were registered on the encoder and decoder to print stack traces of any exceptions.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      //(please note there are 3 classes, for the two beans and the test).


      import java.beans.BeanInfo;
      import java.beans.DefaultPersistenceDelegate;
      import java.beans.IntrospectionException;
      import java.beans.Introspector;
        
      public class ImmutableBean {
        
          //Set up XML persistence delegate
          static {
              try {
                  BeanInfo info = Introspector.getBeanInfo(ImmutableBean.class);
                  info.getBeanDescriptor().setValue("persistenceDelegate",
                          new DefaultPersistenceDelegate(
                                  new String[]{
                                          "a"
                                          })
                          );
                  } catch (IntrospectionException exception) {
                  throw new RuntimeException("Unable to persist ImmutableBean", exception);
              }
          }
            
          int a;
            
          public ImmutableBean(int a) {
              super();
              this.a = a;
          }
          public int getA() {
              return a;
          }
      }
        
        
        
        
      public class ParentBean {
        
          ImmutableBean bean;
            
          public ParentBean() {
              super();
              //Change this line to the commented version to make
              //the encoding work. If default value of "bean" property
              //in this bean is null, then XMLEncoder will bother to encode
              //the actual property, otherwise it will always consider any
              //value of the "bean" property to be the same as the default,
              //and not encode it
              this.bean = new ImmutableBean(1);
              //this.bean = null;
          }
            
          public ImmutableBean getBean() {
              return bean;
          }
          public void setBean(ImmutableBean bean) {
              this.bean = bean;
          }
      }
        
        
        
        
      import java.beans.ExceptionListener;
      import java.beans.XMLDecoder;
      import java.beans.XMLEncoder;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      import java.io.FileOutputStream;
        
      public class ParentBeanTest {
        
          public final static void main(String[] args) {
        
              try {
                    
                  //First encode an ImmutableBean, just to show it works on its own
                  encodeAndDecodeImmutableBean();
        
                  //Now encode/decode the parent bean
                  encodeAndDecodeParentBean();
                    
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
        
          public static void encodeAndDecodeParentBean() throws FileNotFoundException {
              ParentBean parent = new ParentBean();
                
              if (parent.getBean() != null) System.out.println("Default parent.getBean().getA() value: " + parent.getBean().getA());
                
              ImmutableBean newBigBean = new ImmutableBean(47);
                
              parent.setBean(newBigBean);
        
              System.out.println("parent.getBean().getA() value after calling parent.setBean(): " + parent.getBean().getA());
                
              File xmlFile = new File(System.getProperty("user.home"), "ParentBean.xml");
              ParentBean clone = (ParentBean)encodeAndDecode(parent, xmlFile);
                
              System.out.println("parent.getBean().getA() value after XML encoding and decoding: " + clone.getBean().getA());
          }
            
          public static void encodeAndDecodeImmutableBean() throws FileNotFoundException {
              ImmutableBean immutable = new ImmutableBean(254);
              File xmlFile = new File(System.getProperty("user.home"), "ImmutableBean.xml");
              ImmutableBean clone = (ImmutableBean)encodeAndDecode(immutable, xmlFile);
              System.out.println("ImmutableBean a value, should be 254: " + clone.getA());
          }
            
          public static Object encodeAndDecode(Object bean, File file) throws FileNotFoundException {
              XMLEncoder encoder = new XMLEncoder(new FileOutputStream(file));
                
              //Make sure we see any encoder exceptions
              encoder.setExceptionListener(new ExceptionListener() {
                  public void exceptionThrown(Exception e) {
                      e.printStackTrace();
                  }
              });
              encoder.writeObject(bean);
              encoder.close();
                
              //Make sure we see any decoder exceptions
              XMLDecoder decoder = new XMLDecoder(new FileInputStream(file), null,
                      new ExceptionListener() {
                          public void exceptionThrown(Exception e) {
                              e.printStackTrace();
                          }
                      });
                
              return decoder.readObject();
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Setting the default value of the "bean" property in ParentBean default constructor to null causes XMLEncoder to notice the "bean" property has changed. Presumably a custom persistence delegate for ImmutableBean and/or ParentBean could also work.

            Unassigned Unassigned
            ryeung Roger Yeung (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: