-
Enhancement
-
Resolution: Unresolved
-
P4
-
None
-
19
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
Summary
-------
Make DOM collections (e.g.: `NodeList`, etc.) extend `java.lang.Iterable`.
Problem
-------
The DOM collections, that is DOM interfaces with an indexed property getter and a length accessor, are based off the IDL specified in the old DOM specification.
Modern WebIDL defines that the ECMAScript bindings for such interfaces have the `%Symbol.iterator%` property, the Java equivalent of which is `java.lang.Iterable`.
Solution
--------
Make the following DOM collection interfaces extend `java.lang.Iterable` with the `T` type parameter being set to the return type of the `item(int)` method:
- `org.w3c.dom.DOMImplementationList`
- `org.w3c.dom.DOMStringList`
- `org.w3c.dom.NamedNodeMap`
- `org.w3c.dom.NodeList`
- `org.w3c.dom.css.CSSRuleList`
- `org.w3c.dom.css.CSSStyleDeclaration`
- `org.w3c.dom.css.CSSValueList`
- `org.w3c.dom.stylesheets.MediaList`
- `org.w3c.dom.stylesheets.StyleSheetList`
The interfaces should also provide a default implementation for backwards compatibility.
Specification
-------------
`jdk.xml.internal.DefaultDOMIterator`:
```diff
+package jdk.xml.internal;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.function.IntFunction;
+import java.util.function.IntSupplier;
+
+public final class DefaultDOMIterator<T> implements Iterator<T> {
+
+ private final IntFunction<T> itemGetter;
+ private final IntSupplier lengthGetter;
+
+ private int currentIndex = 0;
+
+ private DefaultDOMIterator(IntFunction<T> itemGetter, IntSupplier lengthGetter) {
+ this.itemGetter = itemGetter;
+ this.lengthGetter = lengthGetter;
+ }
+
+ public static <T> DefaultDOMIterator<T> of(IntFunction<T> itemGetter, IntSupplier lengthGetter) {
+ return new DefaultDOMIterator<>(itemGetter, lengthGetter);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return currentIndex < lengthGetter.getAsInt();
+ }
+
+ @Override
+ public T next() {
+ if (currentIndex >= lengthGetter.getAsInt()) {
+ throw new NoSuchElementException();
+ }
+
+ return itemGetter.apply(currentIndex++);
+ }
+}
```
`org.w3c.dom.DOMImplementationList`:
```diff
@@ -50,7 +54,7 @@ package org.w3c.dom;
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
* @since 1.5, DOM Level 3
*/
-public interface DOMImplementationList {
+public interface DOMImplementationList extends Iterable<DOMImplementation> {
/**
* Returns the <code>index</code>th item in the collection. If
* <code>index</code> is greater than or equal to the number of
@@ -69,4 +73,8 @@ public interface DOMImplementationList {
*/
public int getLength();
+ @Override
+ public default Iterator<DOMImplementation> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.DOMStringList`:
```diff
@@ -50,7 +54,7 @@ package org.w3c.dom;
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
* @since 1.5, DOM Level 3
*/
-public interface DOMStringList {
+public interface DOMStringList extends Iterable<String> {
/**
* Returns the <code>index</code>th item in the collection. If
* <code>index</code> is greater than or equal to the number of
@@ -76,4 +80,8 @@ public interface DOMStringList {
*/
public boolean contains(String str);
+ @Override
+ public default Iterator<String> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.NamedNodeMap`:
```diff
@@ -53,7 +57,7 @@ package org.w3c.dom;
* <p><code>NamedNodeMap</code> objects in the DOM are live.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
*/
-public interface NamedNodeMap {
+public interface NamedNodeMap extends Iterable<Node> {
/**
* Retrieves a node specified by name.
* @param name The <code>nodeName</code> of a node to retrieve.
@@ -209,4 +213,8 @@ public interface NamedNodeMap {
String localName)
throws DOMException;
+ @Override
+ public default Iterator<Node> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.NodeList`:
```diff
@@ -49,7 +53,7 @@ package org.w3c.dom;
* index, starting from 0.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
*/
-public interface NodeList {
+public interface NodeList extends Iterable<Node> {
/**
* Returns the <code>index</code>th item in the collection. If
* <code>index</code> is greater than or equal to the number of nodes in
@@ -67,4 +71,8 @@ public interface NodeList {
*/
public int getLength();
+ @Override
+ public default Iterator<Node> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.css.CSSRuleList`:
```diff
@@ -49,7 +53,7 @@ package org.w3c.dom.css;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface CSSRuleList {
+public interface CSSRuleList extends Iterable<CSSRule> {
/**
* The number of <code>CSSRules</code> in the list. The range of valid
* child rule indices is <code>0</code> to <code>length-1</code>
@@ -69,4 +73,8 @@ public interface CSSRuleList {
*/
public CSSRule item(int index);
+ @Override
+ public default Iterator<CSSRule> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.css.CSSStyleDeclaration`:
```diff
@@ -62,7 +65,7 @@ package org.w3c.dom.css;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface CSSStyleDeclaration {
+public interface CSSStyleDeclaration extends Iterable<String> {
/**
* The parsable textual representation of the declaration block
* (excluding the surrounding curly braces). Setting this attribute will
@@ -188,4 +191,8 @@ public interface CSSStyleDeclaration {
*/
public CSSRule getParentRule();
+ @Override
+ public default Iterator<String> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.css.CSSValueList`:
```diff
@@ -52,7 +56,7 @@ package org.w3c.dom.css;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface CSSValueList extends CSSValue {
+public interface CSSValueList extends CSSValue, Iterable<CSSValue> {
/**
* The number of <code>CSSValues</code> in the list. The range of valid
* values of the indices is <code>0</code> to <code>length-1</code>
@@ -72,4 +76,8 @@ public interface CSSValueList extends CSSValue {
*/
public CSSValue item(int index);
+ @Override
+ public default Iterator<CSSValue> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.stylesheets.MediaList`:
```diff
@@ -53,7 +56,7 @@ package org.w3c.dom.stylesheets;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface MediaList {
+public interface MediaList extends Iterable<String> {
/**
* The parsable textual representation of the media list. This is a
* comma-separated list of media.
@@ -111,4 +114,8 @@ public interface MediaList {
public void appendMedium(String newMedium)
throws DOMException;
+ @Override
+ public default Iterator<String> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.stylesheets.StyleSheetList`:
```diff
@@ -49,7 +53,7 @@ package org.w3c.dom.stylesheets;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface StyleSheetList {
+public interface StyleSheetList extends Iterable<StyleSheet> {
/**
* The number of <code>StyleSheets</code> in the list. The range of valid
* child stylesheet indices is <code>0</code> to <code>length-1</code>
@@ -68,4 +72,8 @@ public interface StyleSheetList {
*/
public StyleSheet item(int index);
+ @Override
+ public default Iterator<StyleSheet> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
Summary
-------
Make DOM collections (e.g.: `NodeList`, etc.) extend `java.lang.Iterable`.
Problem
-------
The DOM collections, that is DOM interfaces with an indexed property getter and a length accessor, are based off the IDL specified in the old DOM specification.
Modern WebIDL defines that the ECMAScript bindings for such interfaces have the `%Symbol.iterator%` property, the Java equivalent of which is `java.lang.Iterable`.
Solution
--------
Make the following DOM collection interfaces extend `java.lang.Iterable` with the `T` type parameter being set to the return type of the `item(int)` method:
- `org.w3c.dom.DOMImplementationList`
- `org.w3c.dom.DOMStringList`
- `org.w3c.dom.NamedNodeMap`
- `org.w3c.dom.NodeList`
- `org.w3c.dom.css.CSSRuleList`
- `org.w3c.dom.css.CSSStyleDeclaration`
- `org.w3c.dom.css.CSSValueList`
- `org.w3c.dom.stylesheets.MediaList`
- `org.w3c.dom.stylesheets.StyleSheetList`
The interfaces should also provide a default implementation for backwards compatibility.
Specification
-------------
`jdk.xml.internal.DefaultDOMIterator`:
```diff
+package jdk.xml.internal;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.function.IntFunction;
+import java.util.function.IntSupplier;
+
+public final class DefaultDOMIterator<T> implements Iterator<T> {
+
+ private final IntFunction<T> itemGetter;
+ private final IntSupplier lengthGetter;
+
+ private int currentIndex = 0;
+
+ private DefaultDOMIterator(IntFunction<T> itemGetter, IntSupplier lengthGetter) {
+ this.itemGetter = itemGetter;
+ this.lengthGetter = lengthGetter;
+ }
+
+ public static <T> DefaultDOMIterator<T> of(IntFunction<T> itemGetter, IntSupplier lengthGetter) {
+ return new DefaultDOMIterator<>(itemGetter, lengthGetter);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return currentIndex < lengthGetter.getAsInt();
+ }
+
+ @Override
+ public T next() {
+ if (currentIndex >= lengthGetter.getAsInt()) {
+ throw new NoSuchElementException();
+ }
+
+ return itemGetter.apply(currentIndex++);
+ }
+}
```
`org.w3c.dom.DOMImplementationList`:
```diff
@@ -50,7 +54,7 @@ package org.w3c.dom;
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
* @since 1.5, DOM Level 3
*/
-public interface DOMImplementationList {
+public interface DOMImplementationList extends Iterable<DOMImplementation> {
/**
* Returns the <code>index</code>th item in the collection. If
* <code>index</code> is greater than or equal to the number of
@@ -69,4 +73,8 @@ public interface DOMImplementationList {
*/
public int getLength();
+ @Override
+ public default Iterator<DOMImplementation> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.DOMStringList`:
```diff
@@ -50,7 +54,7 @@ package org.w3c.dom;
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
* @since 1.5, DOM Level 3
*/
-public interface DOMStringList {
+public interface DOMStringList extends Iterable<String> {
/**
* Returns the <code>index</code>th item in the collection. If
* <code>index</code> is greater than or equal to the number of
@@ -76,4 +80,8 @@ public interface DOMStringList {
*/
public boolean contains(String str);
+ @Override
+ public default Iterator<String> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.NamedNodeMap`:
```diff
@@ -53,7 +57,7 @@ package org.w3c.dom;
* <p><code>NamedNodeMap</code> objects in the DOM are live.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
*/
-public interface NamedNodeMap {
+public interface NamedNodeMap extends Iterable<Node> {
/**
* Retrieves a node specified by name.
* @param name The <code>nodeName</code> of a node to retrieve.
@@ -209,4 +213,8 @@ public interface NamedNodeMap {
String localName)
throws DOMException;
+ @Override
+ public default Iterator<Node> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.NodeList`:
```diff
@@ -49,7 +53,7 @@ package org.w3c.dom;
* index, starting from 0.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
*/
-public interface NodeList {
+public interface NodeList extends Iterable<Node> {
/**
* Returns the <code>index</code>th item in the collection. If
* <code>index</code> is greater than or equal to the number of nodes in
@@ -67,4 +71,8 @@ public interface NodeList {
*/
public int getLength();
+ @Override
+ public default Iterator<Node> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.css.CSSRuleList`:
```diff
@@ -49,7 +53,7 @@ package org.w3c.dom.css;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface CSSRuleList {
+public interface CSSRuleList extends Iterable<CSSRule> {
/**
* The number of <code>CSSRules</code> in the list. The range of valid
* child rule indices is <code>0</code> to <code>length-1</code>
@@ -69,4 +73,8 @@ public interface CSSRuleList {
*/
public CSSRule item(int index);
+ @Override
+ public default Iterator<CSSRule> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.css.CSSStyleDeclaration`:
```diff
@@ -62,7 +65,7 @@ package org.w3c.dom.css;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface CSSStyleDeclaration {
+public interface CSSStyleDeclaration extends Iterable<String> {
/**
* The parsable textual representation of the declaration block
* (excluding the surrounding curly braces). Setting this attribute will
@@ -188,4 +191,8 @@ public interface CSSStyleDeclaration {
*/
public CSSRule getParentRule();
+ @Override
+ public default Iterator<String> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.css.CSSValueList`:
```diff
@@ -52,7 +56,7 @@ package org.w3c.dom.css;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface CSSValueList extends CSSValue {
+public interface CSSValueList extends CSSValue, Iterable<CSSValue> {
/**
* The number of <code>CSSValues</code> in the list. The range of valid
* values of the indices is <code>0</code> to <code>length-1</code>
@@ -72,4 +76,8 @@ public interface CSSValueList extends CSSValue {
*/
public CSSValue item(int index);
+ @Override
+ public default Iterator<CSSValue> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.stylesheets.MediaList`:
```diff
@@ -53,7 +56,7 @@ package org.w3c.dom.stylesheets;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface MediaList {
+public interface MediaList extends Iterable<String> {
/**
* The parsable textual representation of the media list. This is a
* comma-separated list of media.
@@ -111,4 +114,8 @@ public interface MediaList {
public void appendMedium(String newMedium)
throws DOMException;
+ @Override
+ public default Iterator<String> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```
`org.w3c.dom.stylesheets.StyleSheetList`:
```diff
@@ -49,7 +53,7 @@ package org.w3c.dom.stylesheets;
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113'>Document Object Model (DOM) Level 2 Style Specification</a>.
* @since 1.4, DOM Level 2
*/
-public interface StyleSheetList {
+public interface StyleSheetList extends Iterable<StyleSheet> {
/**
* The number of <code>StyleSheets</code> in the list. The range of valid
* child stylesheet indices is <code>0</code> to <code>length-1</code>
@@ -68,4 +72,8 @@ public interface StyleSheetList {
*/
public StyleSheet item(int index);
+ @Override
+ public default Iterator<StyleSheet> iterator() {
+ return DefaultDOMIterator.of(this::item, this::getLength);
+ }
}
```