question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using Picocli, how do I require a positional argument and then optional arguments depending on the value of the positional argument

See original GitHub issue

I have a situation where I need to have three mandatory arguments (field1, field2 and field3. I then want the user to enter a command name (mandatory, values can be create, list, etc). The command name must be entered, and must be singular (only one of them can be entered).

Some of the commands will have arguments, some of them will not. How do I handle that?

I tried the following, but I get an error:

ArgGroup has no options or positional parameters, and no subgroups

public class CliParserArgs {
    @Option(names = {"--field1"}, required = true)
    private String field1;

    @Option(names = {"--field2"}, required = true)
    String field2;

    @Option(names={"--field3"}, required = true)
    String field3;

    @Option(names = {"-h", "--help"}, usageHelp = true) boolean help;

    class Create {
        private final String val;
        public Create(final String val) {
            this.val = val;
        }
    }

    class ListObjects {
        private final String val;
        public ListObjects(final String val) {
            this.val = val;
        }
    }

    @ArgGroup(heading = "Command", exclusive = true, multiplicity = "1")
    Create create;
    ListObjects listObjects;

    public static void main(String[] args) {
        CliParserArgs cliParserArgs = new CliParserArgs();
        CommandLine cmd = new CommandLine(cliParserArgs);
        CommandLine.ParseResult parseResult = cmd.parseArgs(args);
        System.err.println("parse results: " + parseResult.matchedArgs().toString());

        try {
        if (cmd.isUsageHelpRequested()) {
            cmd.usage(System.out);
        }
        } catch (CommandLine.ParameterException e) {
            System.err.println("error: " + e.getMessage());
            System.err.println(e.getStackTrace());

        }
    }
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
deiningcommented, Sep 11, 2020

Having a look at your code, I realise that none of your classes has a @Command annonation. These annotations are used to declare classes as commands. This is not only true for the main command, but also for subcommands. And yes, derived from your description, I guess subcommands are what you are looking for. Please have a look at the Subcommands documentation. Also the picocli codebase has a minimal working example on subcommands.

Hopefully, the code below will do what you need:

package test;

import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;

public class CliParserArgs {

    @Command(subcommands = { Create.class, ListObjects.class,
            CommandLine.HelpCommand.class }, name = "MyCommand", mixinStandardHelpOptions = true, version = "x.xx")
    static class CliParserCommand implements Runnable {
        @Option(names = { "--field1" }, required = true)
        private String field1;

        @Option(names = { "--field2" }, required = true)
        String field2;

        @Option(names = { "--field3" }, required = true)
        String field3;

        @Override
        public void run() {
            // nothing to do here
        }
    }

    public static void main(String[] args) {
        CommandLine cmd = new CommandLine(new CliParserCommand());
        int exitCode = cmd.execute(args);
        System.exit(exitCode);
    }
}

@Command(name = "subCreate")
class Create implements Runnable {

    @Option(names = { "-f", "--file" })
    String val;

    @Override
    public void run() {
        // Do whatever create is supposed to do
    }
}

@Command(name = "subListObjects")
class ListObjects implements Runnable {

    @Option(names = { "-v", "--value" })
    String val;

    @Override
    public void run() {
        // Do whatever listobjects is supposed to do
    }
}

I hope this example can serve as a starting point. Don’t hesitate to ask again once you have further questions!

0reactions
remkopcommented, Feb 20, 2020

Great, thank you!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using Picocli, how do I require a positional argument and then ...
It sounds like you want to create a command with subcommands. You can do this in picocli by either marking a method with...
Read more >
CommandLine.Parameters (picocli 4.7.0 API)
For single-value parameters, setting arity = "0..1" makes a positional parameter optional, while setting arity = "1" makes it required. Required parameters that ......
Read more >
picocli - a mighty tiny command line interface
Command line arguments can be separated into options and positional parameters. Options have a name, positional parameters are usually the values that follow ......
Read more >
Quick Guide - Picocli
Any command line arguments that are not subcommands, options or option parameters are interpreted as positional parameters. Use the (zero-based) ...
Read more >
CommandLine.Option (picocli 4.7.0 API)
Returns the default value of this option, before splitting and type conversion. ... By default, all options and positional parameters are included in...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found