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 <[email protected]>
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);
+ }
+ }
+}