Почему парсер по умолчанию (использующий commons-cli) не выдает исключение, когда опция не распознана?

Я хотел бы получить распечатанное справочное сообщение об использовании, когда параметр, указанный в качестве аргумента программы, недопустим (недоступен в списке предопределенных параметров).

      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;

Я печатаю в качестве параметра строку "Тест". Я думал, что из-за неверных опций парсер выбрасывает ParseException, но это не так. Как я могу добиться такого поведения? Возможно ли вообще с этой библиотекой? Теперь он просто пропускает параметры, которые не действительны.

ОБНОВЛЕНИЕ На самом деле он выдает исключение, когда опция имеет префикс "-". Таким образом, '-Test' вызывает исключение, а 'Test' - нет. Мой вопрос в любом случае остается в силе, как заставить парсер выдавать исключение на неверный параметр

3 ответа

Решение

Командные строки имеют два типа ввода, отличные от имени программы, Параметры (которые указываются с - или же --) и то, что я назову параметрами (которые, вероятно, имеют лучшее имя, но я не знаю, что это такое!), которые не имеют префикса. Например, для 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;)) Это также принимает только один аргумент для каждой опции, но, как я уже говорил, это только отправная точка для реализации других модификаций парсера по умолчанию

Да, вы можете создать собственное исключение, например:

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

Другие вопросы по тегам