From 6a59ab534d35af6e8219c21faaafa0a6956319db Mon Sep 17 00:00:00 2001 From: Ronald Brill Date: Mon, 30 Sep 2024 20:36:50 +0200 Subject: [PATCH] Make the map used as singleton read only to avoid side effects. Also the method implementations are much simpler for the empty map. --- .../java/org/htmlunit/html/DomElement.java | 9 --- src/main/java/org/htmlunit/html/DomNode.java | 77 ++++++++++++++++++- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/htmlunit/html/DomElement.java b/src/main/java/org/htmlunit/html/DomElement.java index 66c3d362c0..d2bade3f14 100644 --- a/src/main/java/org/htmlunit/html/DomElement.java +++ b/src/main/java/org/htmlunit/html/DomElement.java @@ -1663,19 +1663,10 @@ public void setInnerHtml(final String source) throws SAXException, IOException { * The {@link NamedNodeMap} to store the node attributes. */ class NamedAttrNodeMapImpl implements Map, NamedNodeMap, Serializable { - protected static final NamedAttrNodeMapImpl EMPTY_MAP = new NamedAttrNodeMapImpl(); - private final OrderedFastHashMap map_; private final DomElement domNode_; private final boolean caseSensitive_; - private NamedAttrNodeMapImpl() { - super(); - domNode_ = null; - caseSensitive_ = true; - map_ = new OrderedFastHashMap<>(0); - } - NamedAttrNodeMapImpl(final DomElement domNode, final boolean caseSensitive) { super(); if (domNode == null) { diff --git a/src/main/java/org/htmlunit/html/DomNode.java b/src/main/java/org/htmlunit/html/DomNode.java index dd932aeb4c..30489d6575 100644 --- a/src/main/java/org/htmlunit/html/DomNode.java +++ b/src/main/java/org/htmlunit/html/DomNode.java @@ -99,6 +99,8 @@ public abstract class DomNode implements Cloneable, Serializable, Node { /** The name of the "element" property. Used when watching property change events. */ public static final String PROPERTY_ELEMENT = "element"; + private static final NamedNodeMap EMPTY_NAMED_NODE_MAP = new ReadOnlyEmptyNamedNodeMapImpl(); + /** The owning page of this node. */ private SgmlPage page_; @@ -662,7 +664,7 @@ public boolean hasAttributes() { */ @Override public NamedNodeMap getAttributes() { - return NamedAttrNodeMapImpl.EMPTY_MAP; + return EMPTY_NAMED_NODE_MAP; } /** @@ -1938,4 +1940,77 @@ public DomElement closest(final String selectorString) { throw new CSSException("Error parsing CSS selectors from '" + selectorString + "': " + e.getMessage(), e); } } + + /** + * An unmodifiable empty {@link NamedNodeMap} implementation. + */ + private static final class ReadOnlyEmptyNamedNodeMapImpl implements NamedNodeMap, Serializable { + private ReadOnlyEmptyNamedNodeMapImpl() { + super(); + } + + /** + * {@inheritDoc} + */ + @Override + public int getLength() { + return 0; + } + + /** + * {@inheritDoc} + */ + @Override + public DomAttr getNamedItem(final String name) { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Node getNamedItemNS(final String namespaceURI, final String localName) { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Node item(final int index) { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Node removeNamedItem(final String name) throws DOMException { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Node removeNamedItemNS(final String namespaceURI, final String localName) { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public DomAttr setNamedItem(final Node node) { + throw new UnsupportedOperationException("ReadOnlyEmptyNamedAttrNodeMapImpl.setNamedItem"); + } + + /** + * {@inheritDoc} + */ + @Override + public Node setNamedItemNS(final Node node) throws DOMException { + throw new UnsupportedOperationException("ReadOnlyEmptyNamedAttrNodeMapImpl.setNamedItemNS"); + } + } }