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

garydgregory 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 42bb20ffd [COLLECTIONS-890] Fix TransformIterator null transformer 
handling (#685)
42bb20ffd is described below

commit 42bb20ffd14dc23dd9db264b3ad9b37bf6f71189
Author: OldTruckDriver <[email protected]>
AuthorDate: Sat Jun 20 00:13:58 2026 +1000

    [COLLECTIONS-890] Fix TransformIterator null transformer handling (#685)
    
    * [COLLECTIONS-890] Fix TransformIterator null transformer handling
    
    transform(I) unconditionally called transformer.apply(source), so a null 
transformer
    threw NullPointerException despite the Javadoc documenting a null 
transformer as
    pass-through. Return the source unchanged when the transformer is null, and 
document on
    the constructor/setTransformer @param and getTransformer @return that the 
transformer
    may be null. Add tests for the null-via-constructor and 
null-via-setTransformer paths.
    
    Reviewed-by: OpenAI Codex
    Reviewed-by: Anthropic Claude Code
    
    * Javadoc
    
    ---------
    
    Co-authored-by: Gary Gregory <[email protected]>
---
 src/changes/changes.xml                            |  1 +
 .../collections4/iterators/TransformIterator.java  | 15 +++----
 .../iterators/TransformIteratorTest.java           | 46 ++++++++++++++++++++++
 3 files changed, 55 insertions(+), 7 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 9c38c53c6..d631a8bc5 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -51,6 +51,7 @@
     <action type="fix" dev="ggregory" due-to="Suhyeon Park, Gary Gregory" 
issue="COLLECTIONS-881">MultiMapUtils.getXXX ensure safe copy (#669).</action>
     <action type="fix" dev="ggregory" due-to="Dexter.k, Gary 
Gregory">Re-validate entries in PredicatedMap/PredicatedCollection readObject 
(#682).</action>
     <action type="fix" dev="ggregory" due-to="Ruiqi Dong, Gary Gregory" 
issue="COLLECTIONS-889">IndexedCollection.remove(Object) removes all values for 
a non-unique index key.</action>
+    <action type="fix" dev="ggregory" due-to="Ruiqi Dong, Gary Gregory" 
issue="COLLECTIONS-890">TransformIterator throws NullPointerException when its 
transformer is null.</action>
     <action type="fix" dev="ggregory" due-to="Maxim Safronov, Gary Gregory" 
issue="COLLECTIONS-878">MapUtils.invertMap() improves HashMap construction 
(#652).</action>
     <action type="fix" dev="ggregory" due-to="Dexter.k, Gary Gregory">Validate 
order and uniqueness invariants in decorator readObject() (#684).</action>
     <!-- ADD -->
diff --git 
a/src/main/java/org/apache/commons/collections4/iterators/TransformIterator.java
 
b/src/main/java/org/apache/commons/collections4/iterators/TransformIterator.java
index f7b4113fd..ed7f1e1d4 100644
--- 
a/src/main/java/org/apache/commons/collections4/iterators/TransformIterator.java
+++ 
b/src/main/java/org/apache/commons/collections4/iterators/TransformIterator.java
@@ -59,7 +59,7 @@ public class TransformIterator<I, O> implements Iterator<O> {
      * then objects will not be transformed.
      *
      * @param iterator  the iterator to use
-     * @param transformer  the transformer to use
+     * @param transformer  the transformer to use, may be null to pass 
elements through unchanged
      */
     public TransformIterator(final Iterator<? extends I> iterator,
                              final Transformer<? super I, ? extends O> 
transformer) {
@@ -79,7 +79,7 @@ public class TransformIterator<I, O> implements Iterator<O> {
     /**
      * Gets the transformer this iterator is using.
      *
-     * @return the transformer.
+     * @return the transformer, may be null.
      */
     public Transformer<? super I, ? extends O> getTransformer() {
         return transformer;
@@ -112,7 +112,7 @@ public class TransformIterator<I, O> implements Iterator<O> 
{
      * Sets the iterator for this iterator to use.
      * If iteration has started, this effectively resets the iterator.
      *
-     * @param iterator  the iterator to use
+     * @param iterator  the iterator to use.
      */
     public void setIterator(final Iterator<? extends I> iterator) {
         this.iterator = iterator;
@@ -122,7 +122,7 @@ public class TransformIterator<I, O> implements Iterator<O> 
{
      * Sets the transformer this the iterator to use.
      * A null transformer is a no-op transformer.
      *
-     * @param transformer  the transformer to use
+     * @param transformer  the transformer to use, may be null to pass 
elements through unchanged.
      */
     public void setTransformer(final Transformer<? super I, ? extends O> 
transformer) {
         this.transformer = transformer;
@@ -132,10 +132,11 @@ public class TransformIterator<I, O> implements 
Iterator<O> {
      * Transforms the given object using the transformer.
      * If the transformer is null, the original object is returned as-is.
      *
-     * @param source  the object to transform
-     * @return the transformed object
+     * @param source  the object to transform, may be null.
+     * @return the transformed object, the original object the transformer is 
null.
      */
+    @SuppressWarnings("unchecked")
     protected O transform(final I source) {
-        return transformer.apply(source);
+        return transformer == null ? (O) source : transformer.apply(source);
     }
 }
diff --git 
a/src/test/java/org/apache/commons/collections4/iterators/TransformIteratorTest.java
 
b/src/test/java/org/apache/commons/collections4/iterators/TransformIteratorTest.java
new file mode 100644
index 000000000..8e6a18e8b
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/collections4/iterators/TransformIteratorTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ *      https://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.iterators;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+class TransformIteratorTest {
+
+    /**
+     * Tests <a 
href="https://issues.apache.org/jira/browse/COLLECTIONS-890";>COLLECTIONS-890</a>.
+     */
+    @Test
+    void testNullTransformerActsAsPassThrough() {
+        final TransformIterator<Integer, Integer> iterator = new 
TransformIterator<>(Arrays.asList(1, 2).iterator(), null);
+
+        assertEquals(Integer.valueOf(1), iterator.next());
+        assertEquals(Integer.valueOf(2), iterator.next());
+    }
+
+    @Test
+    void testSetNullTransformerActsAsPassThrough() {
+        final TransformIterator<Integer, Integer> iterator = new 
TransformIterator<>(Arrays.asList(1, 2).iterator(), i -> i + 1);
+        iterator.setTransformer(null);
+
+        assertEquals(Integer.valueOf(1), iterator.next());
+        assertEquals(Integer.valueOf(2), iterator.next());
+    }
+}

Reply via email to