1

Write cmd interface with Java code used picocli v4.6.3

My case: ./cmd [-a -b [-c]]

user put a,b option or got default value example:

  • user only put: ./cmd x1

    a,b,c option got default value

  • ./cmd x1 -a=a1

    request input b option and vice versa (c option still get default value)

  • ./cmd x1 -c=c1

    a & b option get default value

@Command
public class CMD implements Runnable {

    @Parameters
    private String x;

    
    @ArgGroup(exclusive = false)
    private Group group;

    static class Group {
        @Option(names = "-a", required = true, defaultValue = "aa")
        public static String a;

        @Option(names = "-b", required = true, defaultValue = "bb")
        public static String b;

        @Option(names = "-c", required = false, defaultValue = "cc")
        public static String c;
    }

But it didn't work as I wanted I didn't have the solution

kien bui
  • 1,760
  • 2
  • 17
  • 33

1 Answers1

1

Original Answer

The picocli user manual has a detailed section on assigning default values in argument groups.

Applications need to do both of the below:

  • specify default values in both the @Option annotation, and in the initial value of the @Option-annotated field. (Yes, that means some duplication.)
  • manually instantiate the @ArgGroup-annotated field

For your example, that means:

@Command
public class CMD implements Runnable {

    @Parameters
    private String x;
    
    @ArgGroup(exclusive = false)
    private Group group = new Group();

    static class Group {
        @Option(names = "-a", required = true, defaultValue = "aa")
        public static String a = "aa";

        @Option(names = "-b", required = true, defaultValue = "bb")
        public static String b = "bb";

        @Option(names = "-c", required = false, defaultValue = "cc")
        public static String c = "cc";
    }

Update (Answer #2)

@kienbui pointed out that I missed these requirements:

(...) if -a is specified, then -b becomes mandatory (user input becomes required), and similarly if -b is specified, then -a becomes mandatory. Otherwise, if neither -a nor -b is specified, none of the options are required and default values are assigned to the options that are not specified by the end user.

This can be achieved by making a separate inner arg-group for just options -a and -b, and removing the default values from the option declarations, but initializing them with their default values. For example:

@Command
static class CMD implements Runnable {

    @Parameters
    private String x;

    @ArgGroup(exclusive = false)
    private Group group = new Group();

    static class Group {
        @ArgGroup(exclusive = false)
        private InnerGroup inner = new InnerGroup("aa", "bb"); // default values

        @Option(names = "-c", required = false, defaultValue = "cc")
        public String c = "cc";
    }

    static class InnerGroup {
        // default constructor, used by picocli when
        // one or more options in this group are 
        // matched on the command line
        public InnerGroup() {}

        // this constructor assigns default values,
        // used only when *both* options are missing
        public InnerGroup(String a, String b) {
            this.a = a;
            this.b = b;
        }

        @Option(names = "-a", required = true)
        public String a;

        @Option(names = "-b", required = true)
        public String b;
    }

    @Override
    public void run() {
        System.out.printf("a=%s, b=%s, c=%s, x=%s%n", 
                group.inner.a, group.inner.b, group.c, x);
    }
}
Remko Popma
  • 35,130
  • 11
  • 92
  • 114
  • This solution is not fit my requirement. Example: ./cmd -a a1 => Need request user input b option, but your code used b option with defaul value – kien bui Mar 11 '22 at 07:56
  • -a -b work as acc/pass option. If the user don't input anything, -a -b used default value, user can not input one of them, – kien bui Mar 11 '22 at 08:06
  • 1
    I see... So, your requirement is that _if_ `-a` is specified, then `-b` becomes mandatory (user input becomes _required_), and similarly if `-b` is specified, then `-a` becomes mandatory. Otherwise, if neither `-a` nor `-b` is specified, _none_ of the options are required and default values are assigned to the options that are not specified by the end user. Is this correct? – Remko Popma Mar 15 '22 at 04:10
  • Yes, you are right – kien bui Mar 15 '22 at 06:09
  • @kienbui I updated my answer. Hope this works better. :-) – Remko Popma Mar 16 '22 at 05:53