I'm about to migrate some legacy code to contain less deprecated warnings from 3rd-party libraries. For Apache commons-cli
library (version: 1.3.1) I detected in the official JavaDoc that GnuParser
is deprecated and DefaultParser
should be used instead:
@deprecated since 1.3, use the
{@link DefaultParser}
instead
However, the following code snippet stops working as expected:
Options options = new Options();
Option optionGSTypes = new Option(
"gst","gs-types", true,
"the supported types, comma-separated: article, category, template, all");
optionGSTypes.setArgs(3);
optionGSTypes.setValueSeparator(',');
options.addOption(optionGSTypes);
// ... other options
// parsed option values are correct, yet this is deprecated
CommandLineParser parser = new GnuParser();
CommandLine commands = parser.parse(options, args);
// ... interpret parsed 'commands' and related actual values via CLI
Note that setValueSeparator(',')
is used here to define a custom separator char ,
to enable the CLI to support sevaral gst-types (see code snippet).
As input the following program arguments are used to call the CLI:
java -jar MyCLI.jar -gst category -gsd 4
Obviously, several other arguments might also have been added after the gsd parameter. The expected and correctly parsed options for the separator-less use of the "gst" argument are (via GnuParser
):
However, when I change my code and switch towards the recommended parser via:
CommandLineParser parser = new DefaultParser();
the resulting, parsed values are detected incorrectly as:
Hint: I used a debugger to verify the incorrect result of the parse process via inspecting the field values
in org.apache.commons.cli.Option
via the returned commands
variable.
My expectation would be that the internal change of the parser should not yield different results, as this breaks existing code. Has anyone ever encountered the same behavior with Apache Commons-CLI when switching to DefaultParser
and several option values and custom separators?
Is there a difference in the construction/usage of DefaultParser
that I might have overseen?
I think the problem might be the call to optionGSTypes.setArgs(3);
, according to the JavaDoc, it instructs commons-cli to "Sets the number of argument values this Option can take.", i.e. you instruct commons-cli to take the next three commnadline arguments as arguments for the "gst" argument.
Additionally the setValueSeparator(',')
seems to define what usually the equal sign is used for, (see the JavaDoc), i.e. options with format like "key=value", so not what you are actually looking for.
In your case I think the easiest option is to specify the option argument as simple string and do the parsing yourself. This way you can fully control which values are allowed and also provide a better error message.
Stepping through the code of DefaultParser
, this seems like a bug.
First DefaultParser
recognizes -gst
as a short option by calling Options.hasShortOption("-gst")
which returns true
.
So far so good.
Now when it comes to deciding whether to interpret -gsd
as an argument value to -gst
DefaultParser
needs to figure out if -gsd
is itself an option (and therefore can't be an argument to -gst
). It does so by calling its own isShortOption("-gsd")
. This however returns false
for reasons that become obvious if you look at the code:
private boolean isShortOption(String token)
{
// short options (-S, -SV, -S=V, -SV1=V2, -S1S2)
return token.startsWith("-") && token.length() >= 2 &&
options.hasShortOption(token.substring(1, 2));
}
This extracts the first letter from the -gst
option therefore calling Options.hasShortOption("g")
which returns false
. The code seems to be designed to work for POSIX-style single letter options, but it breaks down for multi-letter single-hyphen options like the ones you are using.
However you turn it, -gst
getting recognized as a short option, but -gsd
not getting recognized seems like a bug to me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With