[ 
https://issues.apache.org/jira/browse/CLI-344?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18010688#comment-18010688
 ] 

Gary D. Gregory edited comment on CLI-344 at 7/29/25 2:37 PM:
--------------------------------------------------------------

In git master and snapshot builds: Fail faster with a more precise 
NullPointerException

NPE is the most precise exception and message

Nevertheless, we can make this a touch better using Java's 
{{Objects.requireNonNull()}} to fail faster with a message specific to the 
argument. The exception is still an NPE, the most precise for this case.

Done in git master and snapshot builds in 
[https://repository.apache.org/content/repositories/snapshots/commons-cli/commons-cli/1.10.0-SNAPSHOT/]


was (Author: garydgregory):
In git master and snapshot builds: Fail faster with a more precise 
NullPointerException

> Option.processValue() throws NullPointerException when passed null value with 
> value separator configured
> --------------------------------------------------------------------------------------------------------
>
>                 Key: CLI-344
>                 URL: https://issues.apache.org/jira/browse/CLI-344
>             Project: Commons CLI
>          Issue Type: Bug
>          Components: Options definition
>    Affects Versions: 1.10.0
>            Reporter: Ruiqi Dong
>            Assignee: Gary D. Gregory
>            Priority: Major
>             Fix For: 1.10.0
>
>         Attachments: Option.java, OptionTest.java
>
>   Original Estimate: 0.5h
>  Remaining Estimate: 0.5h
>
> The {{Option.processValue(String value)}} method does not properly handle 
> null input values. When a null value is passed to this method and the Option 
> has a value separator configured, it throws a {{NullPointerException}} 
> instead of handling the null gracefully with proper validation.
>  
> *Steps to Reproduce:*
> Option option = new Option("D", true, "Define property");
> option.setValueSeparator('=');
> option.processValue(null);  // Throws NullPointerException
>  
> *Expected Behavior:* The method should validate the input and throw an 
> {{IllegalArgumentException}} with a clear error message when null is passed, 
> consistent with how other methods in the library handle invalid input.
> *Actual Behavior:* A {{NullPointerException}} is thrown at line 839 in 
> Option.java when the code attempts to call {{indexOf()}} on the null value:
> java.lang.NullPointerException
>     at org.apache.commons.cli.Option.processValue(Option.java:839)
>  
> *Root Cause Analysis:*
> The {{processValue()}} method assigns the input value directly to a local 
> variable without null checking:
> void processValue(final String value) {
>     if (argCount == UNINITIALIZED) {
>         throw new IllegalArgumentException("NO_ARGS_ALLOWED");
>     }
>     String add = value;  // No null check
>     if (hasValueSeparator()) {
>         final char sep = getValueSeparator();
>         int index = add.indexOf(sep);  // NPE occurs here when add is null
>         // ...
>     }
> }
>  
> *Unit Test Cases:*
> @Test
> public void testProcessValueWithNullThrowsIllegalArgumentException() {
>     Option option = new Option("D", true, "Define property");
>     option.setValueSeparator('=');
>     
>     IllegalArgumentException exception = assertThrows(
>         IllegalArgumentException.class, 
>         () -> option.processValue(null),
>         "processValue(null) should throw IllegalArgumentException"
>     );
>     
>     assertTrue(exception.getMessage().contains("null"),
>         "Exception message should indicate null value issue");
> }
>  
> *Test Results:*
> [*INFO*] Running org.apache.commons.cli.{*}OptionTest{*}{*}{*}
> [*ERROR*] *Tests* {*}run: 1{*}, *Failures: 1*, Errors: 0, Skipped: 0, Time 
> elapsed: 0.001 s *<<< FAILURE!* -- in 
> org.apache.commons.cli.{*}OptionTest{*}{*}{*}
> [*ERROR*] 
> org.apache.commons.cli.OptionTest.testProcessValueWithNullThrowsIllegalArgumentException
>  -- Time elapsed: 0.001 s <<< FAILURE!
> org.opentest4j.AssertionFailedError: processValue(null) should throw 
> IllegalArgumentException ==> Unexpected exception type thrown, expected: 
> <java.lang.IllegalArgumentException> but was: <java.lang.NullPointerException>
>  at 
> org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
>  at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:67)
>  at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:39)
>  at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3153)
>  at 
> org.apache.commons.cli.OptionTest.testProcessValueWithNullThrowsIllegalArgumentException(OptionTest.java:32)
>  at java.lang.reflect.Method.invoke(Method.java:498)
>  at java.util.ArrayList.forEach(ArrayList.java:1259)
>  at java.util.ArrayList.forEach(ArrayList.java:1259)
> Caused by: java.lang.NullPointerException
>  at org.apache.commons.cli.Option.processValue(Option.java:839)
>  at 
> org.apache.commons.cli.OptionTest.lambda$testProcessValueWithNullThrowsIllegalArgumentException$0(OptionTest.java:34)
>  at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:53)
>  ... 6 more
>  
> *Suggested Fix:* 
> Add null validation at the beginning of the method:
> void processValue(final String value) {
>     if (value == null) {
>         throw new IllegalArgumentException("The value must not be null");
>     }
>     if (argCount == UNINITIALIZED) {
>         throw new IllegalArgumentException("NO_ARGS_ALLOWED");
>     }
>     // ... rest of the method remains unchanged
> }



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

Reply via email to