Partha Paul created LANG-1819:
---------------------------------
Summary: ArrayUtils.removeAll() Does Not Throw
IndexOutOfBoundsException for Null Array Input
Key: LANG-1819
URL: https://issues.apache.org/jira/browse/LANG-1819
Project: Commons Lang
Issue Type: Bug
Components: lang.*
Affects Versions: 3.20.0
Environment: * Commons Lang version: (3.20.0 including the current
snapshot version)
* Java version: (javac 17.0.12)
Reporter: Partha Paul
The Javadoc for all ArrayUtils.removeAll() overloads states that
{color:#172b4d}{_}passing a null array should throw an
IndexOutOfBoundsException{_}.{color} However, the actual implementation
silently returns null instead, which violates the documented contract.
h2. Affected Method(s)
All primitive and Object overloads of removeAll(), including but not limited to:
* removeAll(boolean[] array, int... indices)
* removeAll(byte[] array, int... indices)
* removeAll(char[] array, int... indices)
* removeAll(double[] array, int... indices)
* removeAll(float[] array, int... indices)
* removeAll(int[] array, int... indices)
* removeAll(long[] array, int... indices)
* removeAll(short[] array, int... indices)
* removeAll(T[] array, int... indices)
h2. Root Cause
All typed overloads delegate to the generic removeAll(Object array, int...
indices) overload via a cast:
{code:java}
return (boolean[]) removeAll((Object) array, indices);
{code}
When array is null, casting it to Object preserves the null, and the generic
overload returns null silently instead of throwing IndexOutOfBoundsException.
h2. Steps to Reproduce
{code:java}
@Test
void testRemoveAllThrowsIndexOutOfBoundException() {
assertThrows(IndexOutOfBoundsException.class, () ->
ArrayUtils.removeAll((boolean[]) null, 2));
}
{code}
h2. Expected Behavior
Per the Javadoc:
{quote}If the input array is null, an IndexOutOfBoundsException will be thrown,
because in that case no valid index can be specified.
{quote}
An IndexOutOfBoundsException should be thrown.
h2. Actual Behavior
No exception is thrown. The method returns null.
h2. Proposed Fix
There are two valid approaches to resolving this inconsistency, and I am happy
to submit a PR for whichever is preferred:
h3. Option A - Fix the implementation
Add an explicit null check in the generic removeAll(Object, int...) overload:
{code:java}
if (array == null) {
throw new IndexOutOfBoundsException("Array is null, no valid index can be
specified.");
}
{code}
This aligns the implementation with the documented contract, since returning
null for a null array input is arguably surprising and may be an unsafe
behavior.
h3. Option B - Update the documentation
Update the Javadoc across all overloads to reflect the actual behavior:
{code:java}
* If the input array is {@code null}, {@code null} will be returned.
{code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)