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

Exception throws due to the changes in JDK 7 object tranversal and break backward compatibility

    Details

    • Subcomponent:
    • Resolved In Build:
      b12
    • Verification:
      Verified

      Description

      J2SE Version (please include all output from java -version flag):
      7u4


      Does this problem occur on J2SE 6ux or 7ux? Yes / No (pick one)
      No, works fine with 6u32


      Bug Description:

      This issue appears to be due in part to a weird change in ordering in Java 7's object tranversal.

      In Java 6 (note can provide the Java 6 Update 32 version, but it really doesn't change apart from the version number):

          <java version="1.6.0_25" class="java.beans.XMLDecoder">
           <void id="MBeanLoader0" property="owner"/>
           <object id="Emailer0" class="wt.jmx.core.mbeans.Emailer">
            <void id="ArrayList0" property="emailLists">
             <void method="add">
              <object class="wt.jmx.core.mbeans.EmailList">
               <object idref="Emailer0"/>
               <string>JMX-Administrators</string>
               <void property="addressList">
                <string>###@###.###</string>
               </void>
              </object>
             </void>
            </void>
            <void property="emailLists">
             <object idref="ArrayList0"/>
            </void>
            <void property="ownerMBean">
             <object idref="MBeanLoader0"/>
            </void>
           </object>
           ...

      In Java 7:

          <java version="1.7.0_04" class="java.beans.XMLDecoder">
           <void id="MBeanLoader0" property="owner"/>
           <object class="wt.jmx.core.mbeans.Emailer" id="Emailer0">
            <void id="ArrayList0" property="emailLists">
             <void method="add">
              <object class="wt.jmx.core.mbeans.EmailList">
               <object idref="Emailer0">
                <void property="emailLists">
                 <object idref="ArrayList0"/>
                </void>
                <void property="ownerMBean">
                 <object idref="MBeanLoader0"/>
                </void>
               </object>
               <string>JMX-Administrators</string>
               <void property="addressList">
                <string>###@###.###</string>
               </void>
              </object>
             </void>
            </void>
           </object>
           ...

      Java 7's output very slightly more verbose but it also seems to be "eating
      its own tail" more than the Java 6 output, i.e. it's trying to specify
      the emailLists property to be ArrayList0 in the midst of creating ArrayList0.
      The <object idref="Emailer0"> and subsequent <string>JMX-Administrators</string>
      elements are due to setting a persistence delegate of
      "new DefaultPersistenceDelegate( new String[] { "emailer", "name" } )"
      for the EmailList class.

      This change was simply ugly, but the result is that XMLDecoder fails to add
      the EmailList instance to the Emailer instance, so something seems quite broken here.

      Steps to Reproduce (be specific):

      After changing ~70 classes, can once again persist the objects via XMLEncoder.
      The output is, however, substantially different than that produced with Java 6.
      That's fine *but* also get numerous exceptions when reading this XML in with XMLDecoder.
      These are output by the exception listener and are of the form:

      java.lang.NullPointerException: target should not be null
          at java.beans.Statement.invokeInternal(Statement.java:201)
          at java.beans.Statement.access$000(Statement.java:58)
          at java.beans.Statement$2.run(Statement.java:185)
          at java.security.AccessController.doPrivileged(Native Method)
          at java.beans.Statement.invoke(Statement.java:182)
          at java.beans.Expression.getValue(Expression.java:153)
          at com.sun.beans.decoder.ObjectElementHandler.getValueObject(ObjectElementHandler.java:166)
          at com.sun.beans.decoder.NewElementHandler.getValueObject(NewElementHandler.java:123)
          at com.sun.beans.decoder.ElementHandler.endElement(ElementHandler.java:169)
          at com.sun.beans.decoder.DocumentHandler.endElement(DocumentHandler.java:305)
          at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
          at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
          at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
          at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
          at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
          at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
          at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
          at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
          at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
          at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source)
          at com.sun.beans.decoder.DocumentHandler.parse(DocumentHandler.java:356)
          at java.beans.XMLDecoder.parsingComplete(XMLDecoder.java:192)
          at java.beans.XMLDecoder.readObject(XMLDecoder.java:238)
              ...

      One piece that may not be 100% obvious from the XML:

          public synchronized Collection<EmailList> getEmailLists()
          {
            return ( new ArrayList<>( emailLists.values() ) );
          }

          public synchronized void setEmailLists( final Collection<EmailList> newEmailLists )
          {
            for ( EmailList emailList : emailLists.values() )
              emailList.deregister();
            emailLists.clear();
            for ( EmailList inEmailList : newEmailLists )
              addEmailList( inEmailList );
          }

      the nuances here may explain why the new XML fails --

      in that setEmailLists() doesn't literally assign the incoming Collection
      reference to a field but rather clears its internal collection and then
      copies each element from the incoming Collection.

      It would seem that XMLEncoder should work fine with an implementation like this --
      and it did all the way through Java 5 and 6. Reading the Java 7 generation XML,
      however, it would seem that it attempts to assign this Collection to the
      Emailer object before its first element has been successfully created,
      which is clearly not right.
      Seems it is a regression after the 6921644 fix.
      We should set ArrayList later, when it will be initialized.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                malenkov Sergey Malenkov (Inactive)
                Reporter:
                tyao Ting-Yun Ingrid Yao (Inactive)
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: