Skip to content

Fix DefaultParser keeping property values across parses - #450

Merged
garydgregory merged 2 commits into
apache:masterfrom
oscerd:default-parser-properties
Oct 29, 2026
Merged

garydgregory merged 2 commits into
apache:masterfrom
oscerd:default-parser-properties

Conversation

@oscerd

@oscerd oscerd commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

If you reuse an Options instance and pass Properties to DefaultParser.parse(), the first parse leaves the property value behind in the Option registered in Options: handleProperties() called processValue() on that registered option rather than on the copy that goes into the CommandLine, and nothing ever clears it. From then on the same Options gives wrong answers:

  • a later parse with a different property value still returns the first one;
  • -o value on the command line returns the old property value, and value ends up in the argument list;
  • with a -D style option (hasArgs().valueSeparator('=')), pairs from the earlier properties show up in the next parse's getOptionProperties().

The fix adds the value to the copy instead, the same way values from the command line are handled, so parsing no longer changes the values of the registered options. A value the option already has still wins over the property, as testPropertiesPreserveExistingOptionValue() expects, and the parse(Options, Properties, NonOptionAction, String...) Javadoc now says so. The three new tests in DefaultParserTest fail on master and pass with the change.

  • Read the contribution guidelines for this project.
  • Read the ASF Generative Tooling Guidance if you use Artificial Intelligence (AI).
  • I used AI to create any part of, or all of, this pull request. Which AI tool was used to create this pull request, and to what extent did it contribute? Claude Code (Claude Opus 5.5) was used to analyze the issue and to prepare the change, its tests and this description.
  • Run a successful build using the default Maven goal with mvn; that's mvn on the command line by itself.
  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best practice.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request should have a meaningful subject line and body. Note that a maintainer may squash commits during the merge process.

🤖 Generated with Claude Code

@garydgregory

Copy link
Copy Markdown
Member

Hello @oscerd

This PR can break existing applications by throwing IllegalArgumentException when no exception is currently thrown.

Is this intentional? Whether it is or not , this needs to be documented and tested.

Rebase on git master and see DefaultParserTest.testPropertiesPreserveExistingOptionValue().

TY!

When parse() gets a Properties object, handleProperties() called
processValue() on the Option registered in Options instead of on the
copy that goes into the CommandLine, and only when that Option had no
values yet. Nothing ever clears it, so once you've parsed with
properties, reusing the same Options gives stale results: a new
property value is ignored, a value given on the command line is
replaced by the old one and ends up in the argument list, and pairs
from a "-D" style option carry over into the next parse.

Add the value to the copy instead, like values from the command line,
so parsing doesn't change the Options anymore. A value the Option
already has still wins over the property, as before, and the Javadoc
now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@oscerd
oscerd force-pushed the default-parser-properties branch from 2eedfd0 to d19562c Compare October 28, 2026 13:27
@oscerd

oscerd commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Sorry @garydgregory, that wasn't intentional.

The isValuesEmpty() check I removed was also protecting options that already have a value, like the one in your new test, so the property value went into a full list and Option.add() threw.

I put the check back, on the copy this time, so an existing value still wins and Options is still not modified. Rebased on master, your test passes along with the new ones. I also added a short note to the parse(Options, Properties, NonOptionAction, String...) Javadoc about how property values are used.

Thanks for catching it!

Parsing still updates the option group selections, so saying that
options itself isn't modified went too far. Say what actually holds:
property values go into the returned CommandLine without changing the
values of the registered options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@garydgregory
garydgregory merged commit e04b9bc into apache:master Oct 29, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants