JDK-8287076 : Document.normalizeDocument() produces different results
  • Type: Bug
  • Component: xml
  • Sub-Component: org.w3c.dom
  • Affected Version: 10,11,17,18,19
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2022-05-20
  • Updated: 2022-12-09
  • Resolved: 2022-06-23
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 11 JDK 13 JDK 15 JDK 17 JDK 19 JDK 20
11.0.18-oracleFixed 13.0.14Fixed 15.0.10Fixed 17.0.6-oracleFixed 19 b29Fixed 20Fixed
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
JDK 9.0.4 - works
JDK 10.0 onwards (including 18) - cloneMap returns empty list

A DESCRIPTION OF THE PROBLEM :
I was upgrading from Java 8 (works fine) to 11 calculating a digest value on an XML snippet. I was getting different result. Document.normalizeDocument returns different results when crossing over fro 9.0.4 to 10.0 onwards.

To pin point the bug. observer the call: 
DOMNormalizer.namespaceFixUp()
  Line 888: attributes.cloneMap(fAttributeList);

cloneMap does NOT work. NOTE this does not use the return value and replies on fAttributeList being passed by reference.

The implementation of clone map NamedNodeMapImpl.cloneMap():578 has changed. 
Line 580: list = new ArrayList<>(nodes);
This news the method parameter which leaves the reference passed in by DOMNormalizer empty. This worked fine on JDK 9.0.4.

Really the code should be:
fAttributeList = attributes.cloneMap(fAttributeList);
OR the implementation change back

REGRESSION : Last worked in version 8u331

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the source code provider under JDK 9.0.4 and a more recent JDK 10+. Different namespace attribute ordering because NamedNodeMapImpl.cloneMap is not working as intended.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected consistent results and the fAttributeList to be populated from cloneMap.
ACTUAL -
cloneMap is not populating variable fAttributeList 

---------- BEGIN SOURCE ----------
package test;

import java.io.StringWriter;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSParser;
import org.w3c.dom.ls.LSSerializer;

public class main {

  public static void main(final String[] args) {
    try
    {

      final DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();

      final DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");

      final LSParser builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);

      final LSInput input = impl.createLSInput();
      input.setStringData("<xml/>");

      final Document document = builder.parse(input);
      final Element root = document.getDocumentElement();

      // Generate a single element
      final Element element = document.createElement("token");

      final Attr attr = element.getOwnerDocument().createAttributeNS("http://blah.xsd", "wsu");
      attr.setValue("Id");
      element.setAttributeNodeNS(attr);

      final Attr attr2 = element.getOwnerDocument().createAttributeNS("http://blah2.xsd", "wsu2");
      element.setAttributeNodeNS(attr2);

      final Attr attr3 = element.getOwnerDocument().createAttribute("aa");
      element.setAttributeNodeNS(attr3);

      final Attr attr4 = element.getOwnerDocument().createAttribute("zz");
      element.setAttributeNodeNS(attr4);

      final Attr attr5 = element.getOwnerDocument().createAttribute("tt");
      element.setAttributeNodeNS(attr5);

      root.appendChild(element);

      for ( int i = 0; i < element.getAttributes().getLength(); i++ )
      {
        System.out.println(element.getAttributes().item(i).getNodeName());
      }

      //final String originalXML = prettyPrintFromDocument(document);
      System.out.println("PRE normalise " + prettyPrintFromDocument(document));
      document.normalizeDocument();
      System.out.println("POST normalise " + prettyPrintFromDocument(document));

      for ( int i = 0; i < element.getAttributes().getLength(); i++ )
      {
        System.out.println(element.getAttributes().item(i).getNodeName());
      }
    }
    catch ( final Exception ex )
    {
      ex.printStackTrace();
    }
}

/**
 * Pretty prints a DOM document to a String.
 *
 * @param message the DOM document to serialise.
 * @return a string representation of the DOM message parameter.
 */
private static String prettyPrintFromDocument(final Document message) {
  try {
    final DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();

    final DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");

    final LSSerializer writer = impl.createLSSerializer();
    final LSOutput output = impl.createLSOutput();

    final StringWriter sw = new StringWriter();

    output.setEncoding("UTF-8");
    output.setCharacterStream(sw);

    try {
      writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
    } catch (final Exception ignore) {
    }

    writer.write(message, output);

    return sw.toString();
  } catch (final RuntimeException e) {
    throw e;
  } catch (final Exception e) {
    throw new RuntimeException(e);
  }
}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
None at the moment.

Happy to provide more info. Using Eclipse as debugger.

FREQUENCY : always



Comments
A pull request was submitted for review. URL: https://git.openjdk.org/jdk15u-dev/pull/313 Date: 2022-12-09 07:28:01 +0000
09-12-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk13u-dev/pull/440 Date: 2022-12-09 07:12:36 +0000
09-12-2022

Fix request (13u, 15u): backporting for parity with LTS releases. Clean backport with only copyright difference. jaxp and jdk/java/xml tests run OK.
09-12-2022

Fix request [11u] Backport for parity with 11.0.18-oracle. Clean backport. Tests pass. Update: How it was tested: * manually run test from description to verify * run jtreg tier1, tier2, jck runtime to make sure the change did not break anything Risk of the backport to break the VM: very low
29-09-2022

Fix request [17u] Backport for parity with 17.0.6-oracle. Clean backport. Tests pass. Update: How it was tested: * manually run test from description to verify * run jtreg tier1, tier2, jck runtime to make sure the change did not break anything Risk of the backport to break the VM: very low
29-09-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk11u-dev/pull/1372 Date: 2022-09-27 04:20:46 +0000
27-09-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk17u-dev/pull/739 Date: 2022-09-27 04:11:57 +0000
27-09-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk17u-dev/pull/738 Date: 2022-09-27 03:43:54 +0000
27-09-2022

Changeset: 1f9521e6 Author: Joe Wang <joehw@openjdk.org> Date: 2022-06-23 17:12:31 +0000 URL: https://git.openjdk.org/jdk19/commit/1f9521e6cb2f701f8712b4ec941ff1dbb45dad4e
23-06-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk19/pull/59 Date: 2022-06-22 20:01:58 +0000
22-06-2022

The observations on Windows 10: JDK 10ea+27 ,JDK 9 and JDK 8: The outputs are: aa tt wsu wsu2 zz PRE normalise <?xml version="1.0" encoding="UTF-8"?><xml> <token aa="" tt="" xmlns:NS1="http://blah.xsd" NS1:wsu="Id" xmlns:NS2="http://blah2.xsd" NS2:wsu2="" zz=""/> </xml> POST normalise <?xml version="1.0" encoding="UTF-8"?><xml> <token aa="" tt="" NS1:wsu="Id" NS2:wsu2="" xmlns:NS1="http://blah.xsd" xmlns:NS2="http://blah2.xsd" zz=""/> </xml> aa tt NS1:wsu NS2:wsu2 xmlns:NS1 xmlns:NS2 zz JDK 10ea+28, JDK 11, JDK 17, JDK 18, and JDK 19ea+19: The outputs are changed as the following: aa tt wsu wsu2 zz PRE normalise <?xml version="1.0" encoding="UTF-8"?><xml> <token aa="" tt="" xmlns:NS1="http://blah.xsd" NS1:wsu="Id" xmlns:NS2="http://blah2.xsd" NS2:wsu2="" zz=""/> </xml> POST normalise <?xml version="1.0" encoding="UTF-8"?><xml> <token aa="" tt="" xmlns:NS1="http://blah.xsd" NS1:wsu="Id" xmlns:NS2="http://blah2.xsd" NS2:wsu2="" zz=""/> </xml> aa tt wsu wsu2 zz
20-05-2022