Ruiqi Dong created COLLECTIONS-890:
--------------------------------------

             Summary: TransformIterator documents null transformers as 
pass-through, but next() throws NullPointerException
                 Key: COLLECTIONS-890
                 URL: https://issues.apache.org/jira/browse/COLLECTIONS-890
             Project: Commons Collections
          Issue Type: Bug
          Components: Iterator
            Reporter: Ruiqi Dong


*Summary*
`TransformIterator` documents the same contract in three places:
- constructor: null transformer means elements will not be transformed
- `next()`: null transformer means the original element is returned directly
- `setTransformer(...)`: null transformer is a no-op transformer

The implementation does not honor that contract. `next()` always calls 
`transformer.apply(...)`, so a null transformer causes an immediate 
`NullPointerException`.
 
*Affected code*
File: 
`src/main/java/org/apache/commons/collections4/iterators/TransformIterator.java`
{code:java}
public TransformIterator(final Iterator<? extends I> iterator,
                         final Transformer<? super I, ? extends O> transformer) 
{
    this.iterator = iterator;
    this.transformer = transformer;
}

@Override
public O next() {
    return transform(iterator.next());
}

protected O transform(final I source) {
    return transformer.apply(source);
} {code}
The same class also states:
{code:java}
// constructor Javadoc
// If the given transformer is null, then objects will not be transformed.

// next() Javadoc
// If the transformer is null, no transformation occurs and the object
// from the iterator is returned directly.

// setTransformer(...) Javadoc
// A null transformer is a no-op transformer. {code}
*Reproducer*
Add the following test to 
`src/test/java/org/apache/commons/collections4/iterators/TransformIteratorTest.java`:
{code:java}
@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());
} {code}
Run:
{code:java}
mvn -q 
-Dtest=org.apache.commons.collections4.iterators.TransformIteratorTest#testNullTransformerActsAsPassThrough
 test {code}
*Observed behavior*
{code:java}
java.lang.NullPointerException:
Cannot invoke "org.apache.commons.collections4.Transformer.apply(Object)"
because "this.transformer" is null {code}
*Expected behavior*
When the transformer is null, the iterator should behave as an identity 
transform and return the original elements unchanged.
This is not just an undocumented corner case. The public Javadoc explicitly 
promises null-as-pass-through behavior, but the implementation unconditionally 
dereferences the transformer. Callers following the documented contract get a 
runtime failure instead of the advertised semantics.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to