From b13bdbff35c775e20ea16c3d01128b8b17ea3f03 Mon Sep 17 00:00:00 2001 From: Nickita Khylkouski <90287684+nickita-khylkouski@users.noreply.github.com> Date: Mon, 26 Jan 2026 08:08:57 -0800 Subject: [PATCH] Lists.transform: Preserve spliterator characteristics from backing list. --- .../com/google/common/collect/ListsTest.java | 19 +++++++++++++++++++ .../src/com/google/common/collect/Lists.java | 13 +++++++++++++ 2 files changed, 32 insertions(+) diff --git a/guava-tests/test/com/google/common/collect/ListsTest.java b/guava-tests/test/com/google/common/collect/ListsTest.java index bd46674a18d2..542ab8301db2 100644 --- a/guava-tests/test/com/google/common/collect/ListsTest.java +++ b/guava-tests/test/com/google/common/collect/ListsTest.java @@ -57,6 +57,7 @@ import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.RandomAccess; +import java.util.Spliterator; import java.util.concurrent.CopyOnWriteArrayList; import junit.framework.Test; import junit.framework.TestCase; @@ -892,6 +893,24 @@ private static void assertTransformIterator(List list) { assertFalse(iterator.hasNext()); } + @J2ktIncompatible // CopyOnWriteArrayList + @GwtIncompatible // CopyOnWriteArrayList + public void testTransformSpliteratorPreservesCharacteristics() { + // Test for Issue #8165: Lists.transform should preserve spliterator characteristics + CopyOnWriteArrayList cow = new CopyOnWriteArrayList<>(asList(1, 2, 3)); + + // CopyOnWriteArrayList's spliterator has IMMUTABLE characteristic + int cowCharacteristics = cow.spliterator().characteristics(); + assertTrue((cowCharacteristics & Spliterator.IMMUTABLE) != 0); + + // Lists.transform should preserve the IMMUTABLE characteristic + List transformed = transform(cow, x -> x); + int transformedCharacteristics = transformed.spliterator().characteristics(); + assertTrue( + "Lists.transform should preserve IMMUTABLE characteristic from CopyOnWriteArrayList", + (transformedCharacteristics & Spliterator.IMMUTABLE) != 0); + } + public void testPartition_badSize() { List source = singletonList(1); assertThrows(IllegalArgumentException.class, () -> partition(source, 0)); diff --git a/guava/src/com/google/common/collect/Lists.java b/guava/src/com/google/common/collect/Lists.java index 32e032edd1bf..32b0ede09e4d 100644 --- a/guava/src/com/google/common/collect/Lists.java +++ b/guava/src/com/google/common/collect/Lists.java @@ -50,6 +50,7 @@ import java.util.NoSuchElementException; import java.util.Objects; import java.util.RandomAccess; +import java.util.Spliterator; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; import org.jspecify.annotations.Nullable; @@ -605,6 +606,12 @@ public boolean removeIf(Predicate filter) { return fromList.removeIf(element -> filter.test(function.apply(element))); } + @Override + @GwtIncompatible("Spliterator") + public Spliterator spliterator() { + return CollectSpliterators.map(fromList.spliterator(), 0, function); + } + @GwtIncompatible @J2ktIncompatible private static final long serialVersionUID = 0; } @@ -678,6 +685,12 @@ public int size() { return fromList.size(); } + @Override + @GwtIncompatible("Spliterator") + public Spliterator spliterator() { + return CollectSpliterators.map(fromList.spliterator(), 0, function); + } + @GwtIncompatible @J2ktIncompatible private static final long serialVersionUID = 0; }