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