This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git


The following commit(s) were added to refs/heads/master by this push:
     new 634b23dbb COLLECTIONS-842: Deprecate Lists incompatible with Java 21, 
add new variant of AbstractLinkedList (#485)
634b23dbb is described below

commit 634b23dbbbaf64816685b168aedfcfec2dbe00c1
Author: Julian Reschke <julian.resc...@gmx.de>
AuthorDate: Tue May 7 15:54:40 2024 +0200

    COLLECTIONS-842: Deprecate Lists incompatible with Java 21, add new variant 
of AbstractLinkedList (#485)
---
 .../collections4/list/AbstractLinkedList.java      |   2 +
 ...dList.java => AbstractLinkedListForJava21.java} |  32 +--
 .../collections4/list/CursorableLinkedList.java    |   2 +
 .../collections4/list/NodeCachingLinkedList.java   |   2 +
 .../DefaultAbstractLinkedListForJava21Test.java    | 316 +++++++++++++++++++++
 5 files changed, 338 insertions(+), 16 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/collections4/list/AbstractLinkedList.java 
b/src/main/java/org/apache/commons/collections4/list/AbstractLinkedList.java
index aecb2e948..1d66a792f 100644
--- a/src/main/java/org/apache/commons/collections4/list/AbstractLinkedList.java
+++ b/src/main/java/org/apache/commons/collections4/list/AbstractLinkedList.java
@@ -43,7 +43,9 @@ import org.apache.commons.collections4.OrderedIterator;
  *
  * @param <E> the type of elements in this list
  * @since 3.0
+ * @deprecated use {@link AbstractLinkedListForJava21} instead
  */
+@Deprecated
 public abstract class AbstractLinkedList<E> implements List<E> {
 
     /*
diff --git 
a/src/main/java/org/apache/commons/collections4/list/AbstractLinkedList.java 
b/src/main/java/org/apache/commons/collections4/list/AbstractLinkedListForJava21.java
similarity index 96%
copy from 
src/main/java/org/apache/commons/collections4/list/AbstractLinkedList.java
copy to 
src/main/java/org/apache/commons/collections4/list/AbstractLinkedListForJava21.java
index aecb2e948..b6563597d 100644
--- a/src/main/java/org/apache/commons/collections4/list/AbstractLinkedList.java
+++ 
b/src/main/java/org/apache/commons/collections4/list/AbstractLinkedListForJava21.java
@@ -39,12 +39,14 @@ import org.apache.commons.collections4.OrderedIterator;
  * Overridable methods are provided to change the storage node and to change 
how
  * nodes are added to and removed. Hopefully, all you need for unusual 
subclasses
  * is here.
- * </p>
+ * <p>
+ * This is a copy of AbstractLinkedList, modified to be compatible with Java 21
+ * (see COLLECTIONS-842 for details).
  *
  * @param <E> the type of elements in this list
  * @since 3.0
  */
-public abstract class AbstractLinkedList<E> implements List<E> {
+public abstract class AbstractLinkedListForJava21<E> implements List<E> {
 
     /*
      * Implementation notes:
@@ -65,11 +67,11 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
     protected static class LinkedListIterator<E> implements ListIterator<E>, 
OrderedIterator<E> {
 
         /** The parent list */
-        protected final AbstractLinkedList<E> parent;
+        protected final AbstractLinkedListForJava21<E> parent;
 
         /**
          * The node that will be returned by {@link #next()}. If this is equal
-         * to {@link AbstractLinkedList#header} then there are no more values 
to return.
+         * to {@link AbstractLinkedListForJava21#header} then there are no 
more values to return.
          */
         protected Node<E> next;
 
@@ -103,7 +105,7 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
          * @param fromIndex  the index to start at
          * @throws IndexOutOfBoundsException if fromIndex is less than 0 or 
greater than the size of the list
          */
-        protected LinkedListIterator(final AbstractLinkedList<E> parent, final 
int fromIndex)
+        protected LinkedListIterator(final AbstractLinkedListForJava21<E> 
parent, final int fromIndex)
                 throws IndexOutOfBoundsException {
             this.parent = parent;
             this.expectedModCount = parent.modCount;
@@ -219,13 +221,13 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
     }
 
     /**
-     * The sublist implementation for AbstractLinkedList.
+     * The sublist implementation for AbstractLinkedListForJava21.
      *
      * @param <E> the type of elements in this list.
      */
     protected static class LinkedSubList<E> extends AbstractList<E> {
         /** The main list */
-        AbstractLinkedList<E> parent;
+        AbstractLinkedListForJava21<E> parent;
         /** Offset from the main list */
         int offset;
         /** Sublist size */
@@ -233,7 +235,7 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
         /** Sublist modCount */
         int expectedModCount;
 
-        protected LinkedSubList(final AbstractLinkedList<E> parent, final int 
fromIndex, final int toIndex) {
+        protected LinkedSubList(final AbstractLinkedListForJava21<E> parent, 
final int fromIndex, final int toIndex) {
             if (fromIndex < 0) {
                 throw new IndexOutOfBoundsException("fromIndex = " + 
fromIndex);
             }
@@ -522,7 +524,7 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
      * If this constructor is used by a serializable subclass then the init()
      * method must be called.
      */
-    protected AbstractLinkedList() {
+    protected AbstractLinkedListForJava21() {
     }
 
     /**
@@ -530,7 +532,7 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
      *
      * @param coll  the collection to copy
      */
-    protected AbstractLinkedList(final Collection<? extends E> coll) {
+    protected AbstractLinkedListForJava21(final Collection<? extends E> coll) {
         init();
         addAll(coll);
     }
@@ -561,14 +563,12 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
         return true;
     }
 
-    public boolean addFirst(final E o) {
+    public void addFirst(final E o) {
         addNodeAfter(header, o);
-        return true;
     }
 
-    public boolean addLast(final E o) {
+    public void addLast(final E o) {
         addNodeBefore(header, o);
-        return true;
     }
 
     /**
@@ -594,7 +594,7 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
      * {@code value} and inserts it after {@code node}.
      * <p>
      * This implementation uses {@link #createNode(Object)} and
-     * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
+     * {@link 
#addNode(AbstractLinkedListForJava21.Node,AbstractLinkedListForJava21.Node)}.
      *
      * @param node  node to insert after
      * @param value  value of the newly added node
@@ -610,7 +610,7 @@ public abstract class AbstractLinkedList<E> implements 
List<E> {
      * {@code value} and inserts it before {@code node}.
      * <p>
      * This implementation uses {@link #createNode(Object)} and
-     * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
+     * {@link 
#addNode(AbstractLinkedListForJava21.Node,AbstractLinkedListForJava21.Node)}.
      *
      * @param node  node to insert before
      * @param value  value of the newly added node
diff --git 
a/src/main/java/org/apache/commons/collections4/list/CursorableLinkedList.java 
b/src/main/java/org/apache/commons/collections4/list/CursorableLinkedList.java
index 12bce5c70..d39cb1c1a 100644
--- 
a/src/main/java/org/apache/commons/collections4/list/CursorableLinkedList.java
+++ 
b/src/main/java/org/apache/commons/collections4/list/CursorableLinkedList.java
@@ -57,7 +57,9 @@ import java.util.ListIterator;
  *
  * @see java.util.LinkedList
  * @since 1.0
+ * @deprecated parent {@link AbstractLinkedList} is source incompatible with 
List methods added in Java 21
  */
+@Deprecated
 public class CursorableLinkedList<E> extends AbstractLinkedList<E> implements 
Serializable {
 
     /**
diff --git 
a/src/main/java/org/apache/commons/collections4/list/NodeCachingLinkedList.java 
b/src/main/java/org/apache/commons/collections4/list/NodeCachingLinkedList.java
index 1b379dd4d..defd429af 100644
--- 
a/src/main/java/org/apache/commons/collections4/list/NodeCachingLinkedList.java
+++ 
b/src/main/java/org/apache/commons/collections4/list/NodeCachingLinkedList.java
@@ -40,7 +40,9 @@ import java.util.Collection;
  * </p>
  *
  * @since 3.0
+ * @deprecated parent {@link AbstractLinkedList} is source incompatible with 
List methods added in Java 21
  */
+@Deprecated
 public class NodeCachingLinkedList<E> extends AbstractLinkedList<E> implements 
Serializable {
 
     /** Serialization version */
diff --git 
a/src/test/java/org/apache/commons/collections4/list/DefaultAbstractLinkedListForJava21Test.java
 
b/src/test/java/org/apache/commons/collections4/list/DefaultAbstractLinkedListForJava21Test.java
new file mode 100644
index 000000000..79f4c97af
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/collections4/list/DefaultAbstractLinkedListForJava21Test.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4.list;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test case for {@link AbstractLinkedListForJava21}.
+ */
+public class DefaultAbstractLinkedListForJava21Test<E> extends 
AbstractListTest<E> {
+
+    public DefaultAbstractLinkedListForJava21Test() {
+        super(DefaultAbstractLinkedListForJava21Test.class.getSimpleName());
+    }
+
+    protected void checkNodes() {
+        final AbstractLinkedListForJava21<E> list = getCollection();
+        for (int i = 0; i < list.size; i++) {
+            assertEquals(list.getNode(i, false).next, list.getNode(i + 1, 
true));
+            if (i < list.size - 1) {
+                assertEquals(list.getNode(i + 1, false).previous,
+                    list.getNode(i, false));
+            }
+        }
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testAddNodeAfter() {
+        resetEmpty();
+        final AbstractLinkedListForJava21<E> list = getCollection();
+        if (!isAddSupported()) {
+            try {
+                list.addFirst(null);
+            } catch (final UnsupportedOperationException ex) {}
+        }
+
+        list.addFirst((E) "value1");
+        list.addNodeAfter(list.getNode(0, false), (E) "value2");
+        assertEquals("value1", list.getFirst());
+        assertEquals("value2", list.getLast());
+        list.removeFirst();
+        checkNodes();
+        list.addNodeAfter(list.getNode(0, false), (E) "value3");
+        checkNodes();
+        assertEquals("value2", list.getFirst());
+        assertEquals("value3", list.getLast());
+        list.addNodeAfter(list.getNode(0, false), (E) "value4");
+        checkNodes();
+        assertEquals("value2", list.getFirst());
+        assertEquals("value3", list.getLast());
+        assertEquals("value4", list.get(1));
+        list.addNodeAfter(list.getNode(2, false), (E) "value5");
+        checkNodes();
+        assertEquals("value2", list.getFirst());
+        assertEquals("value4", list.get(1));
+        assertEquals("value3", list.get(2));
+        assertEquals("value5", list.getLast());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testGetNode() {
+        resetEmpty();
+        final AbstractLinkedListForJava21<E> list = getCollection();
+        // get marker
+        assertEquals(list.getNode(0, true).previous, list.getNode(0, 
true).next);
+        assertThrows(IndexOutOfBoundsException.class, () -> list.getNode(0, 
false),
+                "Expecting IndexOutOfBoundsException.");
+        list.addAll( Arrays.asList((E[]) new String[]{"value1", "value2"}));
+        checkNodes();
+        list.addFirst((E) "value0");
+        checkNodes();
+        list.removeNode(list.getNode(1, false));
+        checkNodes();
+        assertThrows(IndexOutOfBoundsException.class, () -> list.getNode(2, 
false),
+                "Expecting IndexOutOfBoundsException.");
+        assertThrows(IndexOutOfBoundsException.class, () -> list.getNode(-1, 
false),
+                "Expecting IndexOutOfBoundsException.");
+        assertThrows(IndexOutOfBoundsException.class, () -> list.getNode(3, 
true),
+                "Expecting IndexOutOfBoundsException.");
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testRemoveFirst() {
+        resetEmpty();
+        final AbstractLinkedListForJava21<E> list = getCollection();
+        if (!isRemoveSupported()) {
+            try {
+                list.removeFirst();
+            } catch (final UnsupportedOperationException ex) {}
+        }
+
+        list.addAll(Arrays.asList((E[]) new String[] { "value1", "value2" }));
+        assertEquals("value1", list.removeFirst());
+        checkNodes();
+        list.addLast((E) "value3");
+        checkNodes();
+        assertEquals("value2", list.removeFirst());
+        assertEquals("value3", list.removeFirst());
+        checkNodes();
+        list.addLast((E) "value4");
+        checkNodes();
+        assertEquals("value4", list.removeFirst());
+        checkNodes();
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testRemoveLast() {
+        resetEmpty();
+        final AbstractLinkedListForJava21<E> list = getCollection();
+        if (!isRemoveSupported()) {
+            try {
+                list.removeLast();
+            } catch (final UnsupportedOperationException ex) {}
+        }
+
+        list.addAll(Arrays.asList((E[]) new String[] { "value1", "value2" }));
+        assertEquals("value2", list.removeLast());
+        list.addFirst((E) "value3");
+        checkNodes();
+        assertEquals("value1", list.removeLast());
+        assertEquals("value3", list.removeLast());
+        list.addFirst((E) "value4");
+        checkNodes();
+        assertEquals("value4", list.removeFirst());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testRemoveNode() {
+        resetEmpty();
+        if (!isAddSupported() || !isRemoveSupported()) {
+            return;
+        }
+        final AbstractLinkedListForJava21<E> list = getCollection();
+
+        list.addAll(Arrays.asList((E[]) new String[] { "value1", "value2" }));
+        list.removeNode(list.getNode(0, false));
+        checkNodes();
+        assertEquals("value2", list.getFirst());
+        assertEquals("value2", list.getLast());
+        list.addFirst((E) "value1");
+        list.addFirst((E) "value0");
+        checkNodes();
+        list.removeNode(list.getNode(1, false));
+        assertEquals("value0", list.getFirst());
+        assertEquals("value2", list.getLast());
+        checkNodes();
+        list.removeNode(list.getNode(1, false));
+        assertEquals("value0", list.getFirst());
+        assertEquals("value0", list.getLast());
+        checkNodes();
+    }
+
+    @Override
+    public String getCompatibilityVersion() {
+        return null;
+    }
+
+    @Override
+    protected boolean skipSerializedCanonicalTests() {
+        return true;
+    }
+
+    @Override
+    public AbstractLinkedListForJava21<E> getCollection() {
+        return (AbstractLinkedListForJava21<E>) super.getCollection();
+    }
+
+    @Override
+    public List<E> makeObject() {
+        return new DefaultAbstractLinkedListForJava21<>();
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testSubList() {
+        List<E> list = makeObject();
+        list.add((E) "A");
+        list.add((E) "B");
+        list.add((E) "C");
+        list.add((E) "D");
+        list.add((E) "E");
+
+        assertEquals("[A, B, C, D, E]", list.toString());
+        assertEquals("[A, B, C, D, E]", list.subList(0, 5).toString());
+        assertEquals("[B, C, D, E]", list.subList(1, 5).toString());
+        assertEquals("[C, D, E]", list.subList(2, 5).toString());
+        assertEquals("[D, E]", list.subList(3, 5).toString());
+        assertEquals("[E]", list.subList(4, 5).toString());
+        assertEquals("[]", list.subList(5, 5).toString());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testSubListAddBegin() {
+        List<E> list = makeObject();
+        list.add((E) "A");
+        list.add((E) "B");
+        list.add((E) "C");
+        list.add((E) "D");
+        list.add((E) "E");
+
+        final List<E> sublist = list.subList(0, 0);
+        sublist.add((E) "a");
+        assertEquals("[a, A, B, C, D, E]", list.toString());
+        assertEquals("[a]", sublist.toString());
+        sublist.add((E) "b");
+        assertEquals("[a, b, A, B, C, D, E]", list.toString());
+        assertEquals("[a, b]", sublist.toString());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testSubListAddEnd() {
+        List<E> list = makeObject();
+        list.add((E) "A");
+        list.add((E) "B");
+        list.add((E) "C");
+        list.add((E) "D");
+        list.add((E) "E");
+
+        final List<E> sublist = list.subList(5, 5);
+        sublist.add((E) "F");
+        assertEquals("[A, B, C, D, E, F]", list.toString());
+        assertEquals("[F]", sublist.toString());
+        sublist.add((E) "G");
+        assertEquals("[A, B, C, D, E, F, G]", list.toString());
+        assertEquals("[F, G]", sublist.toString());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testSubListAddMiddle() {
+        List<E> list = makeObject();
+        list.add((E) "A");
+        list.add((E) "B");
+        list.add((E) "C");
+        list.add((E) "D");
+        list.add((E) "E");
+
+        final List<E> sublist = list.subList(1, 3);
+        sublist.add((E) "a");
+        assertEquals("[A, B, C, a, D, E]", list.toString());
+        assertEquals("[B, C, a]", sublist.toString());
+        sublist.add((E) "b");
+        assertEquals("[A, B, C, a, b, D, E]", list.toString());
+        assertEquals("[B, C, a, b]", sublist.toString());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testSubListRemove() {
+        List<E> list = makeObject();
+        list.add((E) "A");
+        list.add((E) "B");
+        list.add((E) "C");
+        list.add((E) "D");
+        list.add((E) "E");
+
+        final List<E> sublist = list.subList(1, 4);
+        assertEquals("[B, C, D]", sublist.toString());
+        assertEquals("[A, B, C, D, E]", list.toString());
+        sublist.remove("C");
+        assertEquals("[B, D]", sublist.toString());
+        assertEquals("[A, B, D, E]", list.toString());
+        sublist.remove(1);
+        assertEquals("[B]", sublist.toString());
+        assertEquals("[A, B, E]", list.toString());
+        sublist.clear();
+        assertEquals("[]", sublist.toString());
+        assertEquals("[A, E]", list.toString());
+    }
+
+    private static class DefaultAbstractLinkedListForJava21<E> extends 
AbstractLinkedListForJava21<E> {
+        DefaultAbstractLinkedListForJava21() {
+            init();
+        }
+
+        private void readObject(final ObjectInputStream in) throws 
IOException, ClassNotFoundException {
+            in.defaultReadObject();
+            doReadObject(in);
+        }
+
+        private void writeObject(final ObjectOutputStream out) throws 
IOException {
+            out.defaultWriteObject();
+            doWriteObject(out);
+        }
+    }
+}

Reply via email to