为什么使用DefaultParser而不是GnuParser时,检测到的CLI选项会有所不同?

24

我即将将一些陈旧的代码迁移,以减少第三方库中过时警告。在Apache commons-cli库(版本:1.3.1)中,我在官方JavaDoc中发现GnuParser已被弃用,应使用DefaultParser代替:

@deprecated since 1.3, use the {@link DefaultParser} instead

但是,以下代码片段的预期行为停止正常工作:

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

请注意,这里使用setValueSeparator(',')来定义自定义分隔符以使CLI支持多个gst类型(请参见代码片段)。

以下程序参数用作调用CLI的输入:

java -jar MyCLI.jar -gst category -gsd 4

显然,在gsd参数之后还可以添加其他几个参数。对于“gst”参数的无分隔符使用,预期且正确解析的选项为(通过GnuParser):

  1. "category"(仅此而已)

然而,当我更改我的代码并转向建议使用的解析器时:

CommandLineParser parser = new DefaultParser();

解析出的值被错误地检测为:

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

提示:我使用调试器通过检查返回的commands变量中的org.apache.commons.cli.Option中的values字段来验证解析过程的不正确结果。

我的期望是解析器的内部更改不应产生不同的结果,因为这会破坏现有的代码。是否有人在切换到DefaultParser和几个选项值和自定义分隔符时遇到过Apache Commons-CLI相同的行为?

我可能忽略了DefaultParser的构建/使用上的差异吗?


这是一个相当深奥的问题,听起来似乎可能是一个错误。建议:您更有可能在Commons邮件列表(user-subscribe@commons.apache.org)中找到一个知识渊博的答案。 - Steve Cohen
“gsd”选项也在选项中配置了吗? - jtahlborn
1
是的,我只是缩短了代码片段。你猜怎么着:当GnuParser负责时它能够正常工作:gst和gsd都被检测到了,符合我的预期。 - MWiesner
我可以重现这个问题! - rzo1
2个回答

8
穿过 DefaultParser 代码,这似乎是个bug。
首先,DefaultParser 通过调用Options.hasShortOption("-gst")-gst 认为是一个短选项,返回 true
到目前为止都很好。
现在,当它决定是否将 -gsd 解释为 -gst 的参数值时,DefaultParser 需要弄清楚 -gsd 是否本身就是一个选项(因此不能是 -gst 的参数)。它通过调用自己的isShortOption("-gsd")来实现。然而,由于看代码时很明显,它返回了 false,原因如下:
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));
}

这会从-gst选项中提取第一个字母,因此调用Options.hasShortOption("g"),返回false。该代码似乎是为POSIX风格的单字母选项设计的,但对于像您使用的多字母单破折号选项而言则存在问题。
无论如何,我认为-gst被识别为短选项,而-gsd未被识别似乎是一个错误。

有趣!会证实我的观察。在查看您的调试结果后,初步得出可能被视为错误的结论似乎是合理的。 - MWiesner

1
我认为问题可能在于对optionGSTypes.setArgs(3);的调用,根据JavaDoc,它指示commons-cli:“设置此选项可以接受的参数值数目”,即您指示commons-cli将下一个三个命令行参数作为“gst”参数的参数。
此外,setValueSeparator(',') 似乎定义了通常使用等号的格式(请参见JavaDoc),即格式为“key = value”的选项,因此不是您实际要查找的内容。
在您的情况下,我认为最简单的选择是将选项参数指定为简单字符串,并自己进行解析。这样,您可以完全控制允许哪些值,并提供更好的错误消息。

我已经阅读了您所提到的JavaDoc片段,但它也适用于正确解析上述程序参数的“GnuParser”。此外,“can have”指的是允许的最大参数数量,在我的用例中可能会发生,因此这实际上就是我要找的。问题是:为什么更改解析器实现会破坏之前正常工作的内容。 - MWiesner
3
那么,要么是DefaultParser中的漏洞,要么是GnuParser中“未记录”的行为,两种情况下,您可能需要直接与commons-cli的维护者讨论,因为只有他们才能确定其中的哪一种情况。 - centic
你可能是对的!我所希望的是:其中一个维护者看到这个 StOf 问题。也许值得一份赏金? - MWiesner
2
Apache项目总是有邮件列表用于此类讨论,因此您最好在那里发布问题,然后维护人员一定会看到。请参阅http://commons.apache.org/proper/commons-cli/mail-lists.html。 - centic
由于我遇到了相同的问题,我联系了Apache邮件列表 - 不幸的是他们还没有回复。 - rzo1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接