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());
+ }
+}