JDK 10+内部Xerces错误
我相信我在JDK 10+中发现了一个明显的错误。我已经向Oracle报告了它,由于我没有任何回应,所以我在这里记录了,也许社区可以确认。此错误在Apache Xerces中不存在,因此这就是解决方法。 document.normalizedocument()返回命名属性属性的JDK 9.0.4的不一致结果。
最终,错误是名为nodemapimpl.clonemap(arrayList列表)更改了实现,并且Domnormalizer称其为依赖于所传递的列表作为方法参数,而不是返回值。如果使用返回值,则不会有错误。
com.sun.org.apache.xerces.internal.dom.domnormalizer:885
// clone content of the attributes
attributes.cloneMap(fAttributeList);
注意此方法依赖于fattributelist在CloneMap中填充并忽略返回值。
如果我们查看JDK 9名为nodemapimpl.clonemap
/**
* NON-DOM: copy content of this map into the specified ArrayList
*
* @param list ArrayList to copy information into.
* @return A copy of this node named map
*/
protected ArrayList cloneMap(ArrayList list) {
if (list == null) {
list = new ArrayList(5);
}
list.clear();
if (nodes != null) {
final int size = nodes.size();
for (int i = 0; i < size; ++i) {
list.add(nodes.get(i));
}
}
return list;
}
现在,我们会查看JDK 10
/**
* NON-DOM: copy content of this map into the specified ArrayList
*
* @param list ArrayList to copy information into.
* @return A copy of this node named map
*/
protected List<Node> cloneMap(List<Node> list) {
if (nodes != null) {
list = new ArrayList<>(nodes);
}
return list;
}
JDK 9清除了通过jdk 10“ News”的参数,该参数在调用Domnoralizer中丢失其参考的参数,没有任何内容。没有任何内容克隆的意思没有对这些属性进行进一步处理。
我认为这是一个明显的错误。谷歌搜索没有打击,除了有人说它值得怀疑。 https://bugs.openjdk.java.java.net/browse/browse/jdk-8233750
这是我在JDK 9下运行的测试,然后是10个观察输出差异。
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("PRE normalise attr " + element.getAttributes().item(i).getNodeName());
}
System.out.println("PRE normalise " + prettyPrintFromDocument(document));
document.normalizeDocument();
for ( int i = 0; i < element.getAttributes().getLength(); i++ )
{
System.out.println("POST normalise attr " + element.getAttributes().item(i).getNodeName());
}
System.out.println("POST normalise " + prettyPrintFromDocument(document));
}
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);
}
}
}
I believe I found a glaring bug in JDK 10+. I've reported it to Oracle and since I've had no response I'm documenting here and maybe the community can confirm. This bug does NOT exist in apache xerces so that is the workaround. Document.normalizeDocument() returns inconsistent results past JDK 9.0.4 for namespaced attributes.
Ultimately the bug is that NamedNodeMapImpl.cloneMap(ArrayList list) changed implementation and DOMNormalizer is calling it relying on the list passed in as a method parameter to be populated rather than the return value. If it used the return value there would be no bug.
com.sun.org.apache.xerces.internal.dom.DOMNormalizer:885
// clone content of the attributes
attributes.cloneMap(fAttributeList);
Note this method is relying on fAttributeList being populated within cloneMap and ignoring the return value.
If we look at JDK 9 NamedNodeMapImpl.cloneMap
/**
* NON-DOM: copy content of this map into the specified ArrayList
*
* @param list ArrayList to copy information into.
* @return A copy of this node named map
*/
protected ArrayList cloneMap(ArrayList list) {
if (list == null) {
list = new ArrayList(5);
}
list.clear();
if (nodes != null) {
final int size = nodes.size();
for (int i = 0; i < size; ++i) {
list.add(nodes.get(i));
}
}
return list;
}
Now we look at JDK 10
/**
* NON-DOM: copy content of this map into the specified ArrayList
*
* @param list ArrayList to copy information into.
* @return A copy of this node named map
*/
protected List<Node> cloneMap(List<Node> list) {
if (nodes != null) {
list = new ArrayList<>(nodes);
}
return list;
}
JDK 9 clears the parameter passed in where JDK 10 "news" the parameter which loses it's reference in the calling DOMNoralizer and no contents are cloned. No contents cloned meaning no further processing on these attributes.
I see this a an obvious bug. Googling around got no hits except for someone saying it was questionable.
https://bugs.openjdk.java.net/browse/JDK-8233750
Here is my test that I run under JDK 9 and then 10 to observes differences in output.
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("PRE normalise attr " + element.getAttributes().item(i).getNodeName());
}
System.out.println("PRE normalise " + prettyPrintFromDocument(document));
document.normalizeDocument();
for ( int i = 0; i < element.getAttributes().getLength(); i++ )
{
System.out.println("POST normalise attr " + element.getAttributes().item(i).getNodeName());
}
System.out.println("POST normalise " + prettyPrintFromDocument(document));
}
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);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论