This is an automated email from the ASF dual-hosted git repository.
daim pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new bda76aba06 OAK-11669 : added Iterators.concat replacement in
oak-commons (#2240)
bda76aba06 is described below
commit bda76aba06c1457b80ec7479a9ff88d63462a8a6
Author: Rishabh Kumar <[email protected]>
AuthorDate: Tue Apr 22 13:45:15 2025 +0530
OAK-11669 : added Iterators.concat replacement in oak-commons (#2240)
Co-authored-by: Rishabh Kumar <[email protected]>
---
.../oak/commons/collections/IteratorUtils.java | 83 ++++++++
.../oak/commons/collections/IteratorUtilsTest.java | 228 +++++++++++++++++++++
2 files changed, 311 insertions(+)
diff --git
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
index ab756ce8b1..b48e109a61 100644
---
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
+++
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
@@ -18,9 +18,11 @@
*/
package org.apache.jackrabbit.oak.commons.collections;
+import org.apache.commons.collections4.iterators.IteratorChain;
import org.apache.commons.collections4.iterators.PeekingIterator;
import org.jetbrains.annotations.NotNull;
+import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
@@ -286,4 +288,85 @@ public class IteratorUtils {
public static <T> Enumeration<T> asEnumeration(final Iterator<T> iterator)
{
return
org.apache.commons.collections4.IteratorUtils.asEnumeration(iterator);
}
+
+ /**
+ * Returns an iterator that iterates through two iterators in sequence.
+ * <p>
+ * This method creates a new iterator that will first iterate through the
elements
+ * in the first iterator and then, when the first iterator is exhausted,
will iterate
+ * through the elements in the second iterator.
+ * <p>
+ * The returned iterator supports {@link Iterator#remove()} if the
provided iterators
+ * support it.
+ *
+ * @param <E> the element type
+ * @param iterator1 the first iterator to chain, may be null
+ * @param iterator2 the second iterator to chain, may be null
+ * @return an iterator that chains the specified iterators together
+ * @throws NullPointerException if any of the iterator is null
+ */
+ public static <E> Iterator<E> chainedIterator(final Iterator<? extends E>
iterator1,
+ final Iterator<? extends E>
iterator2) {
+ return
org.apache.commons.collections4.IteratorUtils.chainedIterator(iterator1,
iterator2);
+ }
+
+ /**
+ * Returns an iterator that iterates through varargs of iterators in
sequence.
+ * <p>
+ * This method creates a new iterator that will first iterate through the
elements
+ * in the first iterator and then, when the first iterator is exhausted,
will iterate
+ * through the elements in the second iterator and so on...
+ * <p>
+ * The returned iterator supports {@link Iterator#remove()} if the
underlying iterator
+ * support it.
+ *
+ * @param <E> the element type
+ * @param iterators array of iterators to chain must not be null
+ * @return an iterator that chains the specified iterators together
+ * @throws NullPointerException if iterators array is null or contains a
null iterator
+ */
+ @SafeVarargs
+ public static <E> Iterator<E> chainedIterator(final Iterator<? extends
E>... iterators) {
+ return
org.apache.commons.collections4.IteratorUtils.chainedIterator(iterators);
+ }
+
+ /**
+ * Returns an iterator that iterates through a collection of iterators in
sequence.
+ * <p>
+ * This method creates a new iterator that will first iterate through the
elements
+ * in the first iterator and then, when the first iterator is exhausted,
will iterate
+ * through the elements in the second iterator and so on...
+ * <p>
+ * The returned iterator supports {@link Iterator#remove()} if the
underlying iterator
+ * support it.
+ *
+ * @param <E> the element type
+ * @param iterators collection of iterators to chain must not be null
+ * @return an iterator that chains the specified iterators together
+ * @throws NullPointerException if an iterators collection is null or
contains a null iterator
+ */
+ public static <E> Iterator<E> chainedIterator(final Collection<Iterator<?
extends E>> iterators) {
+ return
org.apache.commons.collections4.IteratorUtils.chainedIterator(iterators);
+ }
+
+ /**
+ * Returns an iterator that iterates through an iterator of iterators in
sequence.
+ * <p>
+ * This method creates a new iterator that will first iterate through the
elements
+ * in the first iterator and then, when the first iterator is exhausted,
will iterate
+ * through the elements in the second iterator and so on...
+ * <p>
+ * The returned iterator supports {@link Iterator#remove()} if the
underlying iterator
+ * support it.
+ *
+ * @param <E> the element type
+ * @param iterators an iterator of iterators to chain must not be null
+ * @return an iterator that chains the specified iterators together
+ * @throws NullPointerException if an iterators collection is null or
contains a null iterator
+ */
+ public static <E> Iterator<E> chainedIterator(final Iterator<? extends
Iterator<? extends E>> iterators) {
+ final IteratorChain<E> eIteratorChain = new IteratorChain<>();
+ iterators.forEachRemaining(eIteratorChain::addIterator);
+ return eIteratorChain;
+ }
}
diff --git
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
index 0b96cb8df5..47a4393823 100644
---
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
+++
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
@@ -589,4 +589,232 @@ public class IteratorUtilsTest {
Assert.assertEquals(list.get(1), enumeration.nextElement());
Assert.assertFalse(enumeration.hasMoreElements());
}
+
+ @Test
+ public void testChainedIteratorBothNonEmpty() {
+ Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+ Iterator<String> iterator2 = Arrays.asList("c", "d").iterator();
+ Iterator<String> chain = IteratorUtils.chainedIterator(iterator1,
iterator2);
+
+ // it should iterate the elements in order, first from iterator1 and
then from iterator2
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("a", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("b", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("c", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("d", chain.next());
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ @Test
+ public void testChainedIteratorFirstEmpty() {
+ Iterator<String> empty = Collections.emptyIterator();
+ Iterator<String> nonEmpty = Arrays.asList("a", "b").iterator();
+ Iterator<String> chain = IteratorUtils.chainedIterator(empty,
nonEmpty);
+
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("a", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("b", chain.next());
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ @Test
+ public void testChainedIteratorSecondEmpty() {
+ Iterator<String> nonEmpty = Arrays.asList("a", "b").iterator();
+ Iterator<String> empty = Collections.emptyIterator();
+ Iterator<String> chain = IteratorUtils.chainedIterator(nonEmpty,
empty);
+
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("a", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("b", chain.next());
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ @Test
+ public void testChainedIteratorBothEmpty() {
+ Iterator<String> empty1 = Collections.emptyIterator();
+ Iterator<String> empty2 = Collections.emptyIterator();
+ Iterator<String> chain = IteratorUtils.chainedIterator(empty1, empty2);
+
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ @Test
+ public void testChainedIteratorNullFirst() {
+ Iterator<String> nonEmpty = Arrays.asList("a", "b").iterator();
+
+ Assert.assertThrows(NullPointerException.class, () ->
IteratorUtils.chainedIterator(null, nonEmpty));
+ }
+
+ @Test
+ public void testChainedIteratorNullSecond() {
+ Iterator<String> nonEmpty = Arrays.asList("a", "b").iterator();
+
+ Assert.assertThrows(NullPointerException.class, () ->
IteratorUtils.chainedIterator(nonEmpty, null));
+ }
+
+ @Test
+ public void testChainedIteratorBothNull() {
+ Assert.assertThrows(NullPointerException.class, () ->
IteratorUtils.chainedIterator(null, null));
+ }
+
+ @Test
+ public void testChainedIteratorRemove() {
+ List<String> list1 = new ArrayList<>(Arrays.asList("a", "b"));
+ List<String> list2 = new ArrayList<>(Arrays.asList("c", "d"));
+
+ Iterator<String> iterator1 = list1.iterator();
+ Iterator<String> iterator2 = list2.iterator();
+ Iterator<String> chain = IteratorUtils.chainedIterator(iterator1,
iterator2);
+
+ // Remove an element from the first iterator
+ chain.next(); // "a"
+ chain.remove();
+ Assert.assertEquals(List.of("b"), list1);
+
+ // Move to second iterator and remove an element
+ chain.next(); // "b"
+ chain.next(); // "c"
+ chain.remove();
+ Assert.assertEquals(List.of("d"), list2);
+ }
+
+ @Test
+ public void testChainedIteratorRemoveNotSupported() {
+ List<String> list1 = List.of("a", "b");
+ List<String> list2 = new ArrayList<>(Arrays.asList("c", "d"));
+
+ Iterator<String> iterator1 = list1.iterator();
+ Iterator<String> iterator2 = list2.iterator();
+ Iterator<String> chain = IteratorUtils.chainedIterator(iterator1,
iterator2);
+
+ // Remove an element from the first iterator
+ chain.next(); // "a"
+ Assert.assertThrows(UnsupportedOperationException.class,
chain::remove);
+ Assert.assertEquals(List.of("a", "b"), list1);
+
+ // Move to second iterator and remove an element
+ chain.next(); // "b"
+ chain.next(); // "c"
+ chain.remove();
+ Assert.assertEquals(List.of("d"), list2);
+ }
+
+ @Test
+ public void testChainedIteratorWithDifferentTypes() {
+ Iterator<Integer> intIterator = Arrays.asList(1, 2).iterator();
+ Iterator<Double> doubleIterator = Arrays.asList(3.0, 4.0).iterator();
+
+ // Chain iterators with a common supertype
+ Iterator<Number> chain = IteratorUtils.chainedIterator(intIterator,
doubleIterator);
+
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals(1, chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals(2, chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals(3.0, chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals(4.0, chain.next());
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ // for chained Iterator with varargs
+
+ @Test
+ public void testChainedIteratorArrays() {
+ Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+ Iterator<String> iterator2 = Arrays.asList("c", "d").iterator();
+ Iterator<String> iterator3 = Arrays.asList("e", "f").iterator();
+ Iterator<String> chain = IteratorUtils.chainedIterator(iterator1,
iterator2, iterator3);
+
+ // it should iterate the elements in order, first from iterator1 and
then from iterator2
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("a", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("b", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("c", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("d", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("e", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("f", chain.next());
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ @Test
+ public void testChainedIteratorArrayHasNull() {
+ Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+ Iterator<String> iterator2 = Arrays.asList("a", "b").iterator();
+
+ Assert.assertThrows(NullPointerException.class, () ->
IteratorUtils.chainedIterator(iterator1, null, iterator2));
+ }
+
+ @Test
+ public void testChainedIteratorCollection() {
+ Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+ Iterator<String> iterator2 = Arrays.asList("c", "d").iterator();
+ Iterator<String> iterator3 = Arrays.asList("e", "f").iterator();
+ Iterator<String> chain =
IteratorUtils.chainedIterator(List.of(iterator1, iterator2, iterator3));
+
+ // it should iterate the elements in order, first from iterator1 and
then from iterator2
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("a", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("b", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("c", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("d", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("e", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("f", chain.next());
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ @Test
+ public void testChainedIteratorCollectionHasNull() {
+ Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+ Iterator<String> iterator2 = Arrays.asList("a", "b").iterator();
+
+ Assert.assertThrows(NullPointerException.class, () ->
IteratorUtils.chainedIterator(new ArrayList<>(Arrays.asList(iterator1,
iterator2, null))));
+ }
+
+ @Test
+ public void testChainedIterators() {
+ Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+ Iterator<String> iterator2 = Arrays.asList("c", "d").iterator();
+ Iterator<String> iterator3 = Arrays.asList("e", "f").iterator();
+ Iterator<String> chain =
IteratorUtils.chainedIterator(Arrays.asList(iterator1, iterator2,
iterator3).iterator());
+
+ // it should iterate the elements in order, first from iterator1 and
then from iterator2
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("a", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("b", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("c", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("d", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("e", chain.next());
+ Assert.assertTrue(chain.hasNext());
+ Assert.assertEquals("f", chain.next());
+ Assert.assertFalse(chain.hasNext());
+ }
+
+ @Test
+ public void testChainedIteratorsHasNull() {
+ Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+ Iterator<String> iterator2 = Arrays.asList("a", "b").iterator();
+
+ Assert.assertThrows(NullPointerException.class, () ->
IteratorUtils.chainedIterator(new ArrayList<>(Arrays.asList(iterator1,
iterator2, null)).iterator()));
+ }
}