为什么默认解析器(使用 commons-cli)在无法识别选项时不会抛出异常?

Why default parser (using commons-cli) does not throw exception when option is not recognized?

当指定为程序参数的选项无效(在预定义选项列表中不可用)时,我想要打印使用帮助消息。

      CommandLineParser parser = new BasicParser();
    try {
        CommandLine line = parser.parse(getOptions(), args);
    }
    catch( ParseException exp ) {
        getLogger().info("Invalid command line option name. "+exp.getMessage());
        HelpFormatter hf = new HelpFormatter();
        hf.printHelp("destDir", getOptions());
        return false;
    }       
    return true;

我输入 'Test' 字符串作为参数。我在想,无效的选项会导致解析器抛出 ParseException,但事实并非如此。我怎样才能实现这种行为?这个图书馆有可能吗?现在它只是忽略无效的参数。

更新 Actually it throws exception when option has a '-' prefix.所以 '-Test' 导致抛出异常,但 'Test' 不会。我的问题无论如何仍然有效,如何强制解析器在无效参数上抛出异常

是的,你可以,你必须创建自定义异常,如:

public class ParseException extends Exception{
        ParseException(String msg){
             super(msg);  
        }
}

并写入代码:

CommandLineParser parser = new BasicParser();
    try {
        CommandLine line = parser.parse(getOptions(), args);
    }
    catch( Exception exp ) {
       throw new ParseException("Invalid Arguments");
    }       
    return true;

上面的方法应该抛出

throws ParseException

所以它的调用者如果传递无效参数将得到 ParseException

命令行有两种类型的条目,除了程序名称、选项(用 --- 指定)和我将调用的参数(可能有更好的名称但我不知道它是什么!)没有前缀。例如,对于 ls:

ls -la foo

选项是-l-a,参数是foo(要列出的目录)。当您使用 commons-cli 解析命令行时,它 关心选项,它会忽略其他所有内容。这就是为什么如果您添加 Test(不是一个选项)它不会失败,但如果您添加 -Test 则会失败。

虽然 adamreeve 提供的答案非常好并且我接受了,但我决定扩展默认解析器功能以防止输入无效选项,即使没有“-”或“--”符号。我制作了自己的自定义解析器:

public class StrictParser extends Parser {

    @Override
    protected String[] flatten(Options opts, String[] arguments, boolean stopAtNonOption) {
        return arguments;
    }

    @Override
    public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {

        CommandLine cmd = null;
        List<String> tokenList = Arrays.asList(flatten(getOptions(), arguments, stopAtNonOption));
        ListIterator<String> iterator = tokenList.listIterator();

        boolean eatTheRest = false;
        setOptions(options);
        cmd = super.parse(options, arguments, stopAtNonOption);

        while (iterator.hasNext()) {
            String token = (String) iterator.next();
            if (!token.startsWith("--") && !token.startsWith("-")) {
                if (stopAtNonOption) {
                        throw new UnrecognizedOptionException("Unrecognized option: " + token +". Every option must start with '--' or '-'", token);
                }
            } else {
                eatTheRest = true;
            }

            if (eatTheRest) {
                iterator.next();
            }
        }
        return cmd;
    }
}

在此解决方案中,键入任何不带“--”或“-”的 cli 参数都会抛出 UnrecognizedOptionException。这不是完美的解决方案,但它展示了如何做到这一点,并且可以作为其他解决方案的良好起点。例如,我们可以接受不带“--”和“-”的选项,但要检查该选项是否正确。然后我们需要改变

        if (stopAtNonOption) {
                throw new UnrecognizedOptionException("Unrecognized option: " + token +". Every option must start with '--' or '-'", token);
        }

        if (stopAtNonOption) {                  
            if(!getOptions().hasOption(token)){                     
                throw new UnrecognizedOptionException(
                        "Unrecognized option: " + token, token);
            }
        }

(忽略这个丑陋的三个嵌套 ifs ;)) 这也只接受每个选项一个参数,但正如我所提到的,它只是对默认解析器实施其他修改的起点