Search code examples
picocli

Picocli: can the parser be configured using annotations?


I use PicoCLI to parse the arguments. I need to specify setStopAtPositional(true) for one of the subcommands. Is there a way to do this with an annotation? Currently I do this:

cmd.getSubcommands().get("submit").setStopAtPositional(true);

But it would be better to specify it at the method where the submit command is specified to have entire specification in one place.

My class has this structure:

@Command(...)
public class CommandLine implements Callable<Void> {

    @Command(...)
    public void submit( ... options) {
    }
}

Solution

  • Picocli allows different parser configuration for each subcommand, and what you suggest works for your example.

    There is currently no annotation API to configure the parser, it may be an idea to add this in a future release.

    Note that setting the parser configuration via the CommandLine object will change it for that command and its full hierarchy of subcommands and sub-subcommands.

    If you want to change the parser configuration for a single command (without impacting its subcommands), use CommandLine.getCommandSpec().parser() to get its ParserSpec object and do the configuration on that ParserSpec object (example below).

    The question did not mention this, but there may be a concern that it's a bit clunky in picocli 3.9.x to invoke the program after configuration, with the parseWithHandler method. This becomes a bit nicer with the execute method added in picocli 4.0.

    For example:

    @Command(subcommands = B.class)
    class A implements Callable<Integer> {
    }
    
    @Command(name = "B")
    class B implements Callable<Integer> {
    
        @Command
        public int subB(... options) {
        }
    }
    
    public static void main(String... args) {
        CommandLine cmdA = new CommandLine(new A());
    
        // Example 1: configure the B command _and_ its subcommands
        cmdA.getSubcommands().get("B").setStopAtPositional(true);
    
        // Example 2: configure the A command _only_ (not the subcommands)
        cmdA.getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(true);
    
        // parse input and run the command
        int exitCode = cmdA.execute(args);
        System.exit(exitCode);
    }