24

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):

  1. "category" (and nothing else)

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:

  1. "category"
  2. "-gsd"
  3. "4"

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?

MWiesner
  • 8,868
  • 11
  • 36
  • 70
  • That's a pretty deep question and it sounds like it may be a bug. Suggestion: you are more likely to find a knowledgeable answer on the Commons mailing list: user-subscribe@commons.apache.org – Steve Cohen Dec 31 '15 at 17:07
  • is the "gsd" option also configured on the Options? – jtahlborn Jan 15 '16 at 23:52
  • 1
    Yes, it is. I just shortened the code fragment. guess what: it works when `GnuParser` is in charge: both gst and gsd are detected as I would expect it. – MWiesner Jan 15 '16 at 23:57
  • I can reproduce this issue! – rzo1 Jan 19 '16 at 10:24

2 Answers2

8

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.

Sven Schoenung
  • 30,224
  • 8
  • 65
  • 70
  • interesting! would confirm my observations. the conclusion that it might be considered a bug seems reasonable after a first look at your debug findings. – MWiesner Feb 13 '16 at 20:43
1

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.

centic
  • 15,565
  • 9
  • 68
  • 125
  • I read the JavaDoc snippets you refer to, however, it also applied for `GnuParser` which parsed the above program arguments correctly. Moreover, "can have" refers to the maximum allowed number of arguments, which - in my use case - can occur, so this actually is what I'm looking for. The question is: Why is a change in the parser implementation messing up what worked correctly before. – MWiesner Jan 01 '16 at 16:43
  • 3
    Then it is either a bug in `DefaultParser` or an "undocumented" behavior in `GnuParser`, in both cases you will likely need to discuss with the maintainers of commons-cli directly as only they will be able to state which of the two cases it is. – centic Jan 01 '16 at 20:04
  • you may be right! My hope so far: One of the maintainers comes along and finds this StOf question. Maybe it's worth a bounty? – MWiesner Jan 02 '16 at 00:16
  • 2
    Apache projects always have mailing lists for such discussions, your best bet therefore is to post there, then the maintainers will see the question for sure. See http://commons.apache.org/proper/commons-cli/mail-lists.html – centic Jan 03 '16 at 08:54
  • Since I did run into the same issue, I contacted the Apache mailing list - unfortunately they did not answer yet. – rzo1 Jan 19 '16 at 10:25