Search code examples
javapicocli

picocli exception behavior changed?


I'm in the process of updating from picocli 3.9.6 to 4.2.0, and I'm running into an issue when replacing old deprecated calls with the new versions.

In my original version, I had a code block like this:

try {
    return commandLine.parseWithHandlers(
            new RunLast().useOut(ps),
            new ExceptionHandler(),
            args);
}
catch(Exception e) {
    // handle exceptions
}

The ExceptionHandler handles both parameter and execution exceptions -- both are rethrown, but parameter exceptions get the help text added to the exception text. The catch would get hit in cases where, e.g., a command was given bad args. The catch would ensure the error was printed in the UI.

I attempted to update it like this:

try {
    commandLine.setOut(pw);
    ExceptionHandler handler = new ExceptionHandler();
    commandLine.setExecutionExceptionHandler(handler);
    commandLine.setParameterExceptionHandler(handler);
    commandLine.execute(args);
    return commandLine.getExecutionResult();
}
catch(Exception e) {
    // handle exceptions
}

With this new version, exceptions are thrown as before, but they are no longer caught by the catch block after being rethrown by the ExceptionHandler. How can I catch these exceptions?


Solution

  • One of the changes in picocli 4.x is the new execution framework. The user manual has a section on migration that may be useful.

    By design, the CommandLine::execute method never throws an exception. So there is no need to surround the call to CommandLine::execute with a try/catch block (unless you need to catch an Error or Throwable).

    Instead, you can optionally specify custom exception handlers, like you already do in your example. These exception handlers is where you can show an error message to the users. (Perhaps a combination of what was in the previous ExceptionHandler and the logic that previously was in the catch block.)

    The ParameterExceptionHandler is invoked when the user provided invalid input. The default handler shows an error message, may suggest alternative spellings for options or subcommands that look like a typo, and finally displays the usage help message. The Handling Errors section of the user manual has an example ShortErrorMessageHandler that may be useful when the usage help message is so long that it obscures the error message.

    The ExecutionExceptionHandler is invoked when the business logic throws an exception. The default handler just rethrows the exception, which results in a stack trace being printed. The Business Logic Exceptions section of the user manual shows an alternative.

    It sounds like you need a custom ExecutionExceptionHandler that prints a stack trace followed by the usage help message.