The Argparse4j User Manual

Argparse4j is a command line argument parser library for Java based on Python's argparse module. Because of the difference of language features, we cannot use same syntax and usage of original, but we have tried to bring the same touch and feel as much as possible. We also use same terminology as much as possible.

This manual was written based on argparse's manual and most of the the sentences are almost identical, just replaced code examples. We use this approach because argparse manual is well written and since both are do the same thing, using existing manual makes us create a manual with good quality in a short time. Thanks to Python community for the great module and documentation.

We omitted package names from Java classes in this documentation for readability because they tend to be quite long. Most Java programmers use IDE (e.g., eclipse) and it has powerful auto-completion features. And each class in argparse4j has unique name so it is not a big problem after all. The import statements are also omitted from the code snippet by the same reason.

Examples

The following code is a Java program that takes a list of integers and produces either the sum or the max:

public class Prog {

    private static interface Accumulate {
        int accumulate(Collection<Integer> ints);
    }

    private static class Sum implements Accumulate {
        @Override
        public int accumulate(Collection<Integer> ints) {
            int sum = 0;
            for (Integer i : ints) {
                sum += i;
            }
            return sum;
        }

        @Override
        public String toString() {
            return getClass().getSimpleName();
        }
    }

    private static class Max implements Accumulate {
        @Override
        public int accumulate(Collection<Integer> ints) {
            return Collections.max(ints);
        }

        @Override
        public String toString() {
            return getClass().getSimpleName();
        }
    }

    public static void main(String[] args) {
        ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
                .description("Process some integers.");
        parser.addArgument("integers")
                .metavar("N")
                .type(Integer.class)
                .nargs("+")
                .help("an integer for the accumulator");
        parser.addArgument("--sum")
                .dest("accumulate")
                .action(Arguments.storeConst())
                .setConst(new Sum())
                .setDefault(new Max())
                .help("sum the integers (default: find the max)");
        try {
            Namespace res = parser.parseArgs(args);
            System.out.println(((Accumulate) res.get("accumulate"))
                    .accumulate((List<Integer>) res.get("integers")));
        } catch (ArgumentParserException e) {
            parser.handleError(e);
        }
    }
}

It can be run at the command line and provides useful help messages:

$ java Prog -h
usage: prog [-h] [--sum] N [N ...]

Process some integers.

positional arguments:
  N                      an integer for the accumulator

optional arguments:
  -h, --help             show this help message and exit
  --sum                  sum the integers (default: find the max)

When run with the appropriate arguments, it prints either the sum or the max of the command-line integers:

$ java Prog  1 2 3 4
4
$ java Prog  1 2 3 4 --sum
10

If invalid arguments are passed in, it will throw an exception. The user program can catch the exception and show error message:

$ java Prog  a b c
usage: prog [-h] [--sum] N [N ...]
prog: error: argument integers: could not construct class java.lang.Integer from a (For input string: "a")

The following sections walk you through this example.

Creating a parser

The first step using the argparse4j is creating ArgumentParser object. To do this, use ArgumentParsers.newArgumentParser() static method of ArgumentParsers class:

ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
     .description("Process some integers.");

The ArgumentParser object will hold all the information necessary to parse the command line into Java data types.

Adding arguments

Filling an ArgumentParser with information about program arguments is done by making calls to the ArgumentParser.addArgument() method. Generally, this calls tell the ArgumentParser how to take the strings on the command line and turn them into objects. This information is stored and used when ArgumentParser.parseArgs() is called. For example:

parser.addArgument("integers")
        .metavar("N")
        .type(Integer.class)
        .nargs("+")
        .help("an integer for the accumulator");
parser.addArgument("--sum")
        .dest("accumulate")
        .action(Arguments.storeConst())
        .setConst(new Sum())
        .setDefault(new Max())
        .help("sum the integers (default: find the max)");

Later, calling ArgumentParser.parseArgs() will return an Namespace object with two attributes, integers and accumulate. The integers attribute will be a List<Integer> which has one or more ints, and the accumulate attribute will be either the Sum object, if --sum was specified at the command line, or the Max object if it was not.

Passing arguments

ArgumentParser parses arguments through the ArgumentParser.parseArgs() method. This will inspect the command line, convert each argument to the appropriate type and then invoke the appropriate action. In most cases, this means a simple Namespace object will have attributes parsed out of the command line. The following code:

Namespace res = parser.parseArgs(new String[] { "--sum", "7", "-1", "42" });
System.out.println(res);

will display:

Namespace(integers=[7, -1, 42], accumulate=Sum)

In Java, the command line arguments are typically given as String[] argv. To parse the command line, pass this object to ArgumentParser.parseArgs() method.

ArgumentParser objects

To create ArgumentParser object, one can use one of ArgumentParsers.newArgumentParser() static methods of ArgumentParsers class. The following parameters can be specified:

  • prog - The name of the program. This is necessary because main() method in Java does not provide program name.
  • addHelp - Add a -h/--help option to the parser. (default: true).
  • prefixChars - The set of characters that prefix optional arguments. (default: '-')
  • fromFilePrefixChars - The set of characters that prefix file path from which additional arguments are read. (default: null)

After creation of the instance, several additional parameters can be specified using following methods:

The following sections describes how each of these are used.

prog

In Java, the name of the program is not included in the argument in main() method. Because of this, the name of the program must be supplied to ArgumentParsers.newArgumentParser().

addHelp

By default, ArgumentParser objects add an option which simply displays the parser's help message. For example, consider following code:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").help("foo help");
    Namespace res = parser.parseArgs(args);
}

If -h or --help is supplied at the command line, the ArgumentParser will display help message:

$ java Demo --help
usage: prog [-h] [--foo FOO]

optional arguments:
  -h, --help             show this help message and exit
  --foo FOO              foo help

Occasionally, it may be useful to disable the addition of this help option. This can be achieved by passing false as the addHelp argument to ArgumentParsers.newArgumentParser():

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers
        .newArgumentParser("prog", /*addHelp*/ false);
    parser.addArgument("--foo").help("foo help");
    parser.printHelp();
}
$ java Demo
usage: prog [--foo FOO]

optional arguments:
  --foo FOO              foo help

The help option is typically -h/--help. The exception to this is if the prefixChars is specified and does not include -, in which case -h and --help are not valid options. In this case, the first character in prefixChars is used to prefix the help options:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers
        .newArgumentParser("prog", /*addHelp*/ true, /*prefixChars*/ "+/");
    parser.printHelp();
}
$ java Demo
usage: prog [+h]

optional arguments:
  +h, ++help             show this help message and exit

prefixChars

Most command line options will use - as the prefix, e.g. -f/--foo. Parsers that need to support different or additional prefix characters, e.g. for options like +f or /foo, may specify them using the prefixChars to ArgumentParsers.newArgumentParser():

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog", true, /*prefixChars*/ "-+");
    parser.addArgument("+f");
    parser.addArgument("++bar");
    Namespace res = parser.parseArgs(args);
    System.out.println(res);
}
$ java Demo +f X ++bar Y
Namespace(f=X, bar=Y)

The prefixChars argument defaults to - (you can use ArgumentParsers.DEFAULT_PREFIX_CHARS for this). Supplying a set of characters that does not include - will cause -f/--foo options to be disallowed.

fromFilePrefixChars

It is sometimes useful to read arguments from file other than typing them in command line, for example, when lots of arguments are needed. If fromFilePrefixChars is given as non null string, arguments starts with one of these characters are treated as file path and ArgumentParser reads additional arguments from the file. For example:

$ cat args.txt
-f
bar
public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog", true,
            "-", /*fromFilePrefixChars*/ "@");
    parser.addArgument("-f");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ java Demo -f foo @args.txt
Namespace(f=bar)

The each line of the file is treated as one argument. Please be aware that trailing empty lines or line with only white spaces are also considered as arguments, although it is not readily noticeable to the user. The empty line is treated as empty string.

By default, fromFilePrefixChars is null, which means no argument is treated as file path.

ArgumentParser.description()

The ArgumentParser.description() gives a brief description of what the program does and how it works. In help message, the description is displayed between command line usage string and the help messages for the various arguments:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
        .description("A foo that bars");
    parser.printHelp();
}
$ java Demo
usage: prog [-h]

A foo that bars

optional arguments:
-h, --help             show this help message and exit

By default, the description will be line-wrapped so that it fits within the given space.

ArgumentParser.epilog()

Some programs like to display additional description of the program after the description of the arguments. Such text can be specified using ArgumentParser.epilog() method:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
            .description("A foo that bars")
            .epilog("And that's how you'd foo a bar");
    parser.printHelp();
}
$ java Demo
usage: prog [-h]

A foo that bars

optional arguments:
  -h, --help             show this help message and exit

And that's how you'd foo a bar

As with the ArgumentParser.description() method, text specified in ArgumentParser.epilog() is by default line-wrapped.

ArgumentParser.defaultHelp()

The default value of each argument is not by default displayed in help message. Specifying true to ArgumentParser.defaultHelp() method will display the default value of each argument in help message:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
        .defaultHelp(true);
    parser.addArgument("--foo")
        .type(Integer.class)
        .setDefault(42)
        .help("FOO!");
    parser.addArgument("bar")
        .nargs("*")
        .setDefault(1, 2, 3)
        .help("BAR!");
    parser.printHelp();
}
$ java Demo
usage: prog [-h] [-f FOO] [bar [bar ...]]

positional arguments:
  bar                    BAR! (default: [1, 2, 3])

optional arguments:
  -h, --help             show this help message and exit
  -f FOO, --foo FOO      FOO! (default: 42)

ArgumentParser.usage()

By default, ArgumentParser calculates the usage message from the arguments it contains:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").nargs("?").help("foo help");
    parser.addArgument("bar").nargs("+").help("bar help");
    Namespace res = parser.parseArgsOrFail(args);
}
$ java Demo -h
usage: prog [-h] [--foo [FOO]] bar [bar ...]

positional arguments:
  bar                    bar help

optional arguments:
  -h, --help             show this help message and exit
  --foo [FOO]            foo help

The default message can be overridden with the ArgumentParser.usage() method:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
            .usage("${prog} [OPTIONS]");
    parser.addArgument("--foo").nargs("?").help("foo help");
    parser.addArgument("bar").nargs("+").help("bar help");
    Namespace res = parser.parseArgsOrFail(args);
}
$ java Demo -h
usage: prog [OPTIONS]

positional arguments:
  bar                    bar help

optional arguments:
  -h, --help             show this help message and exit
  --foo [FOO]            foo help

The ${prog} literal string in the given usage message will be replaced with the program name prog.

ArgumentParser.version()

The ArgumentParser.version() method sets the string describing program version. It will be displayed when Arguments.version() action is used.

The ${prog} literal string in the given string will be replaced with the program name prog.

The ArgumentParser.addArgument() method

ArgumentParser.addArgument() method creates new Argument object and adds it to ArgumentParser's internal memory and returns the object to the user code. Argument object defines how a single command line argument should be parsed. ArgumentParser.addArgument() method receives nameOrFlags argument, which is either a name or a list of option strings, e.g. "foo" or "-f", "--foo". After obtained Argument object, several parameters can be specified using following methods:

The following sections describe how each of these are used.

nameOrFlags

The ArgumentParser.addArgument() method must know whether an optional argument, like -f or --foo, or a positional argument, like a list of filenames, is expected. The arguments passed to ArgumentParser.addArgument() must therefore be either a series of flags, or a simple argument name. For example, an optional argument could be created like:

parser.addArgument("-f", "--foo");

while a positional argument could be created like:

parser.addArgument("bar");

When ArgumentParser.parseArgs() is called, optional arguments will be identified by the - prefix (or one of prefixChars if it is specified in ArgumentParsers.newArgumentParser(), and the remaining arguments will be assumed to be positional:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-f", "--foo");
    parser.addArgument("bar");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo BAR
Namespace(foo=null, bar=BAR)
$ java Demo BAR --foo FOO
Namespace(foo=FOO, bar=BAR)
$ java Demo --foo FOO
usage: prog [-h] [-f FOO] bar
prog: error: too few arguments

Argument.action()

Argument objects associate command line arguments with actions. These actions can do just about anything with command line arguments associated with them, though most of the actions simply add an attribute to the object returned by ArgumentParser.parseArgs(). The Argument.action() method specifies how the command line arguments should be handled. The supported actions follow.

Arguments.store()

Arguments.store() just stores the argument's value. This is the default action. For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-f", "--foo");
    System.out.println(parser.parseArgs(args));
}
$ java Demo --foo 1
Namespace(foo=1)

Arguments.storeConst()

Arguments.storeConst() stores the value specified by the Argument.setConst(). (Note that by default const value is the rather unhelpful null.) The Arguments.storeConst() action is most commonly used with optional arguments that specify sort of flags. For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").action(Arguments.storeConst()).setConst(42);
    System.out.println(parser.parseArgs(args));
}
$ java Demo --foo
Namespace(foo=42)

Arguments.storeTrue() and Arguments.storeFalse()

Arguments.storeTrue() and Arguments.storeFalse() are special cases of Arguments.storeConst() using for storing values true and false respectively. In addition, they create default values of false and true respectively. For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").action(Arguments.storeTrue());
    parser.addArgument("--bar").action(Arguments.storeFalse());
    parser.addArgument("--baz").action(Arguments.storeFalse());
    System.out.println(parser.parseArgs(args));
}
$ java Demo --foo --bar
Namespace(baz=true, foo=true, bar=false)

Arguments.append()

Arguments.append() stores a list, and appends each argument value to the list. The list is of type List. This is useful to allow an option to be specified multiple times. For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").action(Arguments.append());
    System.out.println(parser.parseArgs(args));
}
$ java Demo --foo 1 --foo 2
Namespace(foo=[1, 2])

Arguments.appendConst()

Arguments.appendConst() stores a list, and appends the value specified by Argument.setConst() to the list. (Note that the const value defaults to null.) The list is of type List. The Arguments.appendConst() action is typically useful when multiple arguments need to store constants to the same list. For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--str")
        .dest("types")
        .action(Arguments.appendConst())
        .setConst(String.class);
    parser.addArgument("--int")
        .dest("types")
        .action(Arguments.appendConst())
        .setConst(Integer.class);
    System.out.println(parser.parseArgs(args));
}
$ java Demo --str --int
Namespace(types=[class java.lang.String, class java.lang.Integer])

Arguments.count()

Arguments.count() counts the number of times an option occurs. For example, this is useful for increasing verbosity levels:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--verbose", "-v").action(Arguments.count());
    Namespace res = parser.parseArgsOrFail(args);
    System.out.println(res);
}
$ java Demo -vvv
Namespace(verbose=3)

Arguments.version()

Arguments.version() prints version string specified by ArgumentParser.version() and exists when invoked:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("PROG")
        .version("${prog} 2.0");
    parser.addArgument("--version").action(Arguments.version());
    System.out.println(parser.parseArgs(args));
}
$ java Demo --version
PROG 2.0

Arguments.help()

Arguments.help() prints help message and exits when invoked:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog", /*defaultHelp*/ false);
    parser.addArgument("--help").action(Arguments.help());
    System.out.println(parser.parseArgs(args));
}
$ java Demo --help
usage: prog [--help]

optional arguments:
  --help

Custom actions

You can also specify your custom action by implementing ArgumentAction interface. For example:

private static class FooAction implements ArgumentAction {

    @Override
    public void run(ArgumentParser parser, Argument arg,
            Map<String, Object> attrs, String flag, Object value)
            throws ArgumentParserException {
        System.out.printf("%s '%s' %s\n", attrs, value, flag);
        attrs.put(arg.getDest(), value);

    }

    @Override
    public void onAttach(Argument arg) {
    }

    @Override
    public boolean consumeArgument() {
        return true;
    }
}

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    FooAction fooAction = new FooAction();
    parser.addArgument("--foo").action(fooAction);
    parser.addArgument("bar").action(fooAction);
    System.out.println(parser.parseArgs(args));
}
$ java Demo  1 --foo 2
{foo=null, bar=null} '1' null
{foo=null, bar=1} '2' --foo
Namespace(foo=2, bar=1)

Argument.nargs()

ArgumentParser objects usually associate a single command line argument with a single action to be taken. The Argument.nargs() associate different number of command line arguments with a single action. The supported values are:

  • N (an integer). N arguments from the command line will be gathered into a List. For example:

    public static void main(String[] args) throws ArgumentParserException {
        ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
        parser.addArgument("--foo").nargs(2);
        parser.addArgument("bar").nargs(1);
        System.out.println(parser.parseArgs(args));
    }
    
    $ java Demo c --foo a b
    Namespace(foo=[a, b], bar=[c])
    

    Note that nargs(1) produces a list of one item. This is different from the default, in which the item is produced by itself.

  • "?". One argument will be consumed from the command line if possible, and produced as a single item. If no command line argument is present, the value from Argument.setDefault() will be produced. Note that for optional arguments, there is an additional case - the option string is present but not followed by a command line argument. In this case the value from Argument.setConst() will be produced. Some examples to illustrate this:

    public static void main(String[] args) throws ArgumentParserException {
        ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
        parser.addArgument("--foo").nargs("?").setConst("c").setDefault("d");
        parser.addArgument("bar").nargs("?").setDefault("d");
        System.out.println(parser.parseArgs(args));
    }
    
    $ java Demo XX --foo YY
    Namespace(foo=YY, bar=XX)
    $ java Demo XX --foo
    Namespace(foo=c, bar=XX)
    $ java Demo
    Namespace(foo=d, bar=d)
    

    One of the more common usage of nargs("?") is to allow optional input and output files:

    public static void main(String[] args) throws ArgumentParserException {
        ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
        parser.addArgument("infile").nargs("?").type(FileInputStream.class)
                .setDefault(System.in);
        parser.addArgument("outfile").nargs("?").type(PrintStream.class)
                .setDefault(System.out);
        System.out.println(parser.parseArgs(args));
    }
    
    $ java Demo input.txt output.txt
    Namespace(infile=java.io.FileInputStream@4ce86da0, outfile=java.io.PrintStream@2f754ad2)
    $ java Demo
    Namespace(infile=java.io.BufferedInputStream@e05d173, outfile=java.io.PrintStream@1ff9dc36)
    

    It is not obvious that outfile points to output.txt from the abolve output, but it is actually PrintStream to outfile.txt.

  • "*". All command line arguments present are gathered into a List. Note that it generally does not make sense to have more than one positional argument with nargs("*"), but multiple optional arguments with nargs("*") is possible. For example:

    public static void main(String[] args) throws ArgumentParserException {
        ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
        parser.addArgument("--foo").nargs("*");
        parser.addArgument("--bar").nargs("*");
        parser.addArgument("baz").nargs("*");
        System.out.println(parser.parseArgs(args));
    }
    
    $ java Demo
    Namespace(baz=[], foo=null, bar=null)
    $ java Demo a b --foo x y --bar 1 2
    Namespace(baz=[a, b], foo=[x, y], bar=[1, 2])
    
  • "+". Just like "*", all command line arguments present are gathered into a List. Additionally, an error message will be generated if there wasn't at least one command line argument present. For example:

    public static void main(String[] args) {
        ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
        parser.addArgument("foo").nargs("+");
        try {
            System.out.println(parser.parseArgs(args));
        } catch (ArgumentParserException e) {
            parser.handleError(e);
        }
    }
    
    $ java Demo a b
    Namespace(foo=[a, b])
    $ java Demo
    usage: prog [-h] foo [foo ...]
    prog: error: too few arguments
    

If Argument.nargs() is not used, the number of arguments consumed is determined by the Argument.action(). Generally this means a single command line argument will be consumed and a single item(not a List) will be produced. Please note that Argument.nargs() are ignored if one of Arguments.storeConst(), Arguments.appendConst(), Arguments.storeTrue() and Arguments.storeFalse() is provided. More specifically, subclass of ArgumentAction whose consumeArgument() returns false ignores Argument.nargs().

In argparse4j 0.5.0 or earlier, nargs("*") or nargs("+") for positional argument greedily consume all available positional arguments. For example, if we have the following program:

public static void main(String[] args) {
    ArgumentParser ap = ArgumentParsers.newArgumentParser("prog");
    ap.addArgument("foo").nargs("*");
    ap.addArgument("bar");
    ap.parseArgsOrFail(args);
}

If we give 1, 2, 3, 4, and 5 as command-line arguments, foo consumes everything. Because bar is required, the program will show error "too few arguments". Since argparse4j 0.6.0, nargs("*") or nargs("+") for positional argument leave arguments to the remaining positional arguments to satisfy them with the minimum number of arguments. In the above example, foo now consumes only 1, 2, 3, and 4, and leaves 5 to bar, because bar is required argument, and consumes just 1 argument.

Argument.setConst()

The Argument.setConst() is used to hold constant values that are not read from the command line but are required for the various actions. The two most common uses of it are:

Argument.setDefault()

All optional arguments and some positional arguments may be omitted at the command line. The Argument.setDefault() specifies what value should be used if the command line argument is not present. The default value defaults to null. For optional arguments, the default value is used when the option string was not present at the command line:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").setDefault(42);
    System.out.println(parser.parseArgs(args));
}
$ java Demo --foo 2
Namespace(foo=2)
$ java Demo
Namespace(foo=42)

For positional arguments with nargs("?") or nargs("*"), the default value is used when no command line argument was present:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("foo").nargs("?").setDefault(42);
    System.out.println(parser.parseArgs(args));
}
$ java Demo a
Namespace(foo=a)
$ java Demo
Namespace(foo=42)

Providing Arguments.SUPPRESS causes no attribute to be added if the command ine argument was not present:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").setDefault(Arguments.SUPPRESS);
    System.out.println(parser.parseArgs(args));
}
$ java Demo
Namespace()
$ java Demo --foo 1
Namespace(foo=1)

Argument.type()

By default, ArgumentParser objects read command line arguments in as simple strings. However, quite often the command line string should instead be interpreted as another type, like a Float or Integer. The Argument.type() allows any necessary type-checking and type conversions to be performed. The Classes which have valueOf() static method with 1 String argument or a constructor with 1 String argument can be passed directly:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("foo").type(Integer.class);
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo 100
Namespace(foo=100)

As a convenience, if one of following primitive types (boolean.class, byte.class, short.class, int.class, long.class, float.class and double.class) is specified, it is converted to its wrapped type counterpart. For example, if int.class is given, it is automatically converted to Integer.class.

Passing Boolean.class to Argument.type() has a caveat. Since it relies on Boolean.valueOf method, any string which matches "true" in case-insensitive fashion is converted to Boolean.TRUE, and other strings are converted to Boolean.FALSE:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
            .defaultHelp(true);
    parser.addArgument("-f").type(Boolean.class);

    Namespace res = parser.parseArgsOrFail(args);
    System.out.printf("f=%b\n", res.get("f"));
}
$ java Demo -f TRue
f=true
$ java Demo -f foo
f=false

If more strict boolean conversion is desirable, use Arguments.booleanType(). It only allows input string true as true value, and false as false value. Otherwise, reports error:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
            .defaultHelp(true);
    parser.addArgument("-f").type(Arguments.booleanType());

    Namespace res = parser.parseArgsOrFail(args);
    System.out.printf("f=%b\n", res.get("f"));
}
$ java Demo -f true
f=true
$ java Demo -f TRue
usage: prog [-h] [-f {true,false}]
prog: error: argument  -f:  could  not  convert  'TRue'  (choose from {true,
false})
$ java Demo -f foo
usage: prog [-h] [-f {true,false}]
prog: error: argument  -f:  could  not  convert  'foo'  (choose  from {true,
false})

If application wants to change the valid input strings which can be converted to true/false values, use Arguments.booleanType(). For example, to use yes, and no as true and false values respectively instead of true and false:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
            .defaultHelp(true);
    parser.addArgument("-f").type(Arguments.booleanType("yes", "no"));

    Namespace res = parser.parseArgsOrFail(args);
    System.out.printf("f=%b\n", res.get("f"));
}
$ java Demo -f yes
f=true
$ java Demo -f no
f=false
$ java Demo -f true
usage: prog [-h] [-f {yes,no}]
prog: error: argument -f: could not convert 'true' (choose from {yes,no})

The Argument.type() can accept enums. Since enums have limited number of members, type conversion effectively acts like a choice from members. For example:

enum Enums {
    FOO, BAR, BAZ
}

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-x").type(Enums.class);
    try {
        Namespace res = parser.parseArgs(args);
        System.out.println(res);
        Enums x = (Enums) res.get("x");
        System.out.printf("x=%s\n", x.name());
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ java Demo -x BAR
Namespace(x=BAR)
x=BAR
$ java Demo -h
usage: prog [-h] [-x X]

optional arguments:
  -h, --help             show this help message and exit
  -x X

The available enum values are automatically used as metavar, if metavar and choices are not explicitly set by application:

parser.addArgument("-x").type(Enums.class);
$ java Demo -h
usage: prog [-h] [-x {FOO,BAR,BAZ}]

optional arguments:
  -h, --help             show this help message and exit
  -x {FOO,BAR,BAZ}

To limit enum values to choose from, specify them in Argument.choices():

parser.addArgument("-x").type(Enums.class).choices(Enums.FOO, Enums.BAZ);
$ java Demo -h
usage: prog [-h] [-x {FOO,BAZ}]

optional arguments:
  -h, --help             show this help message and exit
  -x {FOO,BAZ}

There is a caveat when Enum.toString() method is overridden. For instance:

enum Lang {
    PYTHON, JAVA, CPP {
        @Override
        public String toString() {
            return "C++";
        }
    }
}

...

parser.addArgument("--lang").type(Lang.class).choices(Lang.values());

We override toString() method of enum CPP. The help message prints fine:

usage: prog [-h] [--lang {PYTHON,JAVA,C++}]

But when we supply "C++" as parameter to --lang, argparse4j complains like so:

prog: error: argument --lang:  could  not  convert  'C++'  to  Lang (No enum
constant Demo.Lang.C++)

This is because Argument.type() does not take into account toString() method override, and it still accepts "CPP" as parameter (e.g., --lang CPP). We could not fix treatment of enum within Argument.type(), since it could break existing code. So, we introduced Arguments.enumStringType() method (it returns object EnumStringArgumentType which implements ArgumentType we will talk abount soon). It uses solely toString() method when converting String to enum value. If we use this new type instead:

parser.addArgument("--lang")
        .type(Arguments.enumStringType(Lang.class));

Passing --lang "C++" just works as expected. Please note that --lang CPP no longer works in this case.

The Argument.type() has a version which accepts an object which implements ArgumentType interface:

private static class PerfectSquare implements ArgumentType<Integer> {

    @Override
    public Integer convert(ArgumentParser parser, Argument arg, String value)
            throws ArgumentParserException {
        try {
            int n = Integer.parseInt(value);
            double sqrt = Math.sqrt(n);
            if (sqrt != (int) sqrt) {
                throw new ArgumentParserException(String.format(
                        "%d is not a perfect square", n), parser);
            }
            return n;
        } catch (NumberFormatException e) {
            throw new ArgumentParserException(e, parser);
        }
    }
}

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("foo").type(new PerfectSquare());
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo 9
Namespace(foo=9)
$ java Demo 7
usage: prog [-h] foo
prog: error: 7 is not a perfect square

The Argument.choices() may be more convenient for type checkers that simply check against a range of values:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("foo").type(Integer.class)
            .choices(Arguments.range(5, 10));
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo 7
Namespace(foo=7)
$ java Demo 11
usage: prog [-h] foo
prog: error: foo expects value in range [5, 10], inclusive

See Argument.choices() for more details.

In some cases, type itself may infer metavar. In that case, it is more convenient to get metavar from type instead of setting metavar for each argument. To achieve this, if MetavarInference is implemented as well, it can infer metavar through its interface method. We mentioned that special handling of Boolean.class for default metavar in Argument.metavar() section. It is implemented using MetavarInference. Here is an example of implementation of MetavarInference.inferMetavar() from ReflectArgumentType:

@Override
public String[] inferMetavar() {
    if (!Boolean.class.equals(type_)) {
        return null;
    }

    return new String[] { TextHelper.concat(
            new String[] { "true", "false" }, 0, ",", "{", "}") };
}

Argument.choices()

Some command line arguments should be selected from a restricted set of values. These can be handled by passing a list of objects to Argument.choices(). When the command line is parsed, argument values will be checked, and an error message will be displayed if the argument was not one of the accepted values:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("foo").choices("a", "b", "c");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo c
Namespace(foo=c)
$ java Demo X
usage: prog [-h] {a,b,c}
prog: error: argument foo: invalid choice: 'X' (choose from {a,b,c})

Note that inclusion in the choices list is checked after any type conversions have been performed. If a list of value is not enough, you can create your own by subclassing ArgumentChoice. For example, argparse4j provides Arguments.range() to check whether an integer is in specified range:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("foo").type(Integer.class)
            .choices(Arguments.range(1, 10));
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo 1
Namespace(foo=1)
$ java Demo 11
usage: prog [-h] foo
prog: error: foo expects value in range [1, 10], inclusive

Please pay attention to the type specified in Argument.type() and type in Argument.choices(). If they are not compatible, subclass of RuntimeException will be thrown.

Argument.required()

In general, the ArgumentParser assumes that flags like -f and --bar indicate optional arguments, which can always be omitted at the command line. To make an option required, true can be specified for Argument.required():

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").required(true);
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo --foo BAR
Namespace(foo=BAR)
$ java Demo
usage: prog [-h] --foo FOO
prog: error: argument --foo is required

As the example shows, if an option is marked as required, ArgumentParser.parseArgs() will report an error if that option is not present at the command line. Argument.required() will be ignored for positional arguments.

Note

Required options are generally considered bad form because users expect options to be optional, and thus they should be avoided when possible.

Argument.help()

Argument.help() method can take string containing a brief description of the argument. When a user requests help (usually by using -h or --help at the command line), these help descriptions will be displayed with each argument:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").action(Arguments.storeTrue())
            .help("foo the bars before frobbling");
    parser.addArgument("bar").nargs("+").help("one of the bars to be frobbled");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo  -h
usage: prog [-h] [--foo] bar [bar ...]

positional arguments:
  bar                    one of the bars to be frobbled

optional arguments:
  -h, --help             show this help message and exit
  --foo                  foo the bars before frobbling

The help strings are used as is: no special string replacement will not be done.

The argparse4j supports silencing the help entry for certain options, by passing Arguments.SUPPRESS to Argument.help() method:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").help(Arguments.SUPPRESS);
    try {
        Namespace ns = parser.parseArgs(args);
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo -h
usage: prog [-h]

optional arguments:
  -h, --help             show this help message and exit

Argument.metavar()

When ArgumentParser generates help messages, it need some way to referer to each expected argument. By default, ArgumentParser objects use the "dest" value (see Argument.dest() about "dest" value) as the "name" of each object. If Boolean.class is given to Argument.type(), and if no metavar and no choices are set, {true,false} is used as metavar automatically for convenience. Similarly, if enum type is given, and if no metavar and no choices are set, a metavar containing their all names is automatically used for convenience (these names are from Enum.names() instead of Enum.toString()). By default, for positional arguments, the dest value is used directly, and for optional arguments, the dest value is uppercased. So, a single positional argument with dest("bar") will be referred to as bar. A single optional argument --foo that should be followed by a single command line argument will be referred to as FOO. For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo");
    parser.addArgument("bar");
    parser.printHelp();
}
$ java Demo
usage: prog [-h] [--foo FOO] bar

positional arguments:
  bar

optional arguments:
  -h, --help             show this help message and exit
  --foo FOO

An alternative name can be specified with Argument.metavar() method:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").metavar("YY");
    parser.addArgument("bar").metavar("XX");
    parser.printHelp();
}
$ java Demo
usage: prog [-h] [--foo YY] XX

positional arguments:
  XX

optional arguments:
  -h, --help             show this help message and exit
  --foo YY

Note that Argument.metavar() method only changes the displayed name - the name of the attribute in the object returned by ArgumentParser.parseArgs() method is still determined by the dest value. Different values of Argument.nargs() may cause the metavar to be used multiple times. Providing multiple values to Argument.metavar() method specifies a different display for each of the arguments:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-x").nargs(2);
    parser.addArgument("--foo").nargs(2).metavar("bar", "baz");
    parser.printHelp();
}
$ java Demo
usage: prog [-h] [-x X X] [--foo bar baz]

optional arguments:
  -h, --help             show this help message and exit
  -x X X
  --foo bar baz

If the number of values specified in Argument.metavar() is not sufficient for the number of arguments given in Argument.nargs(), the last value of metavar is repeated.

Argument.dest()

Most ArgumentParser actions add some values as an attribute of the object returned by ArgumentParser.parseArgs() method. The name of this attribute is determined by "dest". For positional arguments, dest is normally supplied as the first argument to ArgumentParser.addArgument() method, with any internal - converted to _:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("bar");
    parser.addArgument("foo-bar");
    System.out.println(parser.parseArgs(args));
}
$ java Demo XX YY
Namespace(bar=XX, foo_bar=YY)

For optional arguments, the value of dest is normally inferred from the option strings. ArgumentParser generates the value of dest by taking the first long option string and stripping away the initial -- string. If no long option strings were supplied, dest will be derived from the first short option string by stripping the initial - character. Any internal - characters will be converted to _. The example below illustrate this behavior:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-f", "--foo-bar", "--foo");
    parser.addArgument("-x", "-y");
    System.out.println(parser.parseArgs(args));
}
$ java Demo  -f 1 -x 2
Namespace(x=2, foo_bar=1)
$ java Demo  --foo 1 -y 2
Namespace(x=2, foo_bar=1)

Argument.dest() method allows a custom attribute name to be provided:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").dest("bar");
    System.out.println(parser.parseArgs(args));
}
$ java Demo --foo XX
Namespace(bar=XX)

The ArgumentParser.parseArgs() method

ArgumentParser.parseArgs() method converts argument strings to objects and populates Namespace object with these values. The populated Namespace object is returned. Previous calls to ArgumentParser.addArgument() method determine exactly what objects are created and how they are assigned. See the documentation for Adding arguments for details.

ArgumentParser also provides a way to populate attributes other than using Namespace object. See The Namespace object for details.

Option value syntax

ArgumentParser.parseArgs() method supports several ways of specifying the value of an option (if it takes one). In the simplest case, the option and its value are passed as two separate arguments:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-x");
    parser.addArgument("--foo");
    System.out.println(parser.parseArgs(args));
}
$ java Demo -x X
Namespace(foo=null, x=X)
$ java Demo --foo FOO
Namespace(foo=FOO, x=null)

For long options (options with names longer than single character), the option and value can also be passed as a single command line argument, using = to separate them:

$ java Demo --foo=FOO
Namespace(foo=FOO, x=null)

For short options (options only one character long), the option and its value can be concatenated:

$ java Demo -xX
Namespace(foo=null, x=X)

Several short options can be joined together, using only a single - prefix, as long as only the last option (or none of them) requires a value:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-x").action(Arguments.storeTrue());
    parser.addArgument("-y").action(Arguments.storeTrue());
    parser.addArgument("-z");
    System.out.println(parser.parseArgs(args));
}
$ java Demo -xyzZ
Namespace(z=Z, y=true, x=true)

Invalid arguments

While parsing the command line, ArgumentParser.parseArgs() method checks for a variety of errors, including invalid types, invalid options, wrong number of positional arguments, etc. When it encounters such an error, it throws ArgumentParserException. The typical error handling is catch the exception and use ArgumentParser.handleError() method to print error message and exit the program:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").type(Integer.class);
    parser.addArgument("bar").nargs("?");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ java Demo --foo spam
usage: prog [-h] [--foo FOO] [bar]
prog: error: argument --foo: could not convert 'spam' to Integer (For input string: "spam")
$ java Demo --bar
usage: prog [-h] [--foo FOO] [bar]
prog: error: unrecognized arguments: --bar
$ java Demo spam badger
usage: prog [-h] [--foo FOO] [bar]
prog: error: unrecognized arguments: badger

Arguments containing "-"

ArgumentParser.parseArgs() method attempts to give errors whenever the user has cearly made a mistake, but some situations are inherently ambiguous. For example, the command line argument -1 could either be an attempt to specify an option or an attempt to provide a positional argument. The ArgumentParser.parseArgs() method is cautious here: positional arguments may only begin with - if they look like negative numbers and there are no options in the parser that look like negative numbers:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-x");
    parser.addArgument("foo").nargs("?");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ # no negative number options, so -1 is a positional argument
$ java Demo -x -1
Namespace(foo=null, x=-1)
$ # no negative number options, so -1 and -5 are positional arguments
$ java Demo -x -1 -5
Namespace(foo=-5, x=-1)
public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("-1").dest("one");
    parser.addArgument("foo").nargs("?");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ # negative number options present, so -1 is an option
$ java Demo -1 X
Namespace(one=X, foo=null)
$ # negative number options present, so -2 is an option
$ java Demo -2
usage: prog [-h] [-1 ONE] [foo]
prog: error: unrecognized arguments: -2
$ # negative number options present, so both -1s are options
$ java Demo -1 -1
usage: prog [-h] [-1 ONE] [foo]
prog: error: argument -1: expected one argument

If you have positional arguments that must begin with - and don't look like negative numbers, you can insert the pseudo-argument -- which tells ArgumentParser.parseArgs() method that everything after that is a positional argument:

$ java Demo -- -f
Namespace(one=null, foo=-f)

Please note that whatever prefixChars is specified in ArgumentParsers.newArgumentParser() method, pseudo-argument is --.

After --, sub-command cannot be recognized.

Argument abbreviations

The ArgumentParser.parseArgs() method allows long options to be abbreviated if the abbreviation is unambiguous:

public static void main(String[] args) {
    ArgumentParser ap = ArgumentParsers.newArgumentParser("prog");
    ap.addArgument("-bacon");
    ap.addArgument("-badger");
    Namespace res = ap.parseArgsOrFail(args);
    System.out.println(res);
}
$ java Demo -bac MMM
Namespace(bacon=MMM, badger=null)
$ java Demo -bad WOOD
Namespace(bacon=null, badger=WOOD)
$ java Demo -ba BA
usage: prog [-h] [-bacon BACON] [-badger BADGER]
prog: error: ambiguous option: -ba could match -bacon, -badger

An error is produced for arguments that could produce more than one options.

The Namespace object

Namespace object is used to store attributes as a result of ArgumentParser.parseArgs() method. It is just a wrapper to Map and several shortcut getter methods are provided. The actual attributes are stored in Map object and can be retrieved using Namespace.getAttrs() method.

You don't have to use Namespace object. You can directly populate attributes to your Map object using ArgumentParser.parseArgs() method.

You can also assign values to user defined object. In this case, you can use Arg annotation to designate where the attribute to be stored. To specify the name of attribute to assign, use Arg.dest; if it is not specified the name of the attribute or the method will be used instead. For example:

private static class Option {

    @Arg(dest = "filename")
    public String filename;

    @Arg(dest = "rows")
    public int matrix[][];

    @Arg
    public String url;
}

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--rows").type(Integer.class).nargs("+")
            .action(Arguments.append()).metavar("N");
    parser.addArgument("--filename");
    parser.addArgument("--url");

    Option opt = new Option();
    try {
        parser.parseArgs(args, opt);
        System.out.println("outusername=" + opt.filename);
        System.out.println("outurl=" + opt.url);
        int rows = opt.matrix.length;
        for (int i = 0; i < rows; ++i) {
            int cols = opt.matrix[i].length;
            for (int j = 0; j < cols; ++j) {
                System.out.printf("%d\t", opt.matrix[i][j]);
            }
            System.out.println();
        }
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ java Demo --rows 1 2 3 --rows 4 5 6 --filename out --url http://example.com
outusername=out
http://example.com
1    2       3
4    5       6

As shown above, argparse4j supports simple List to array conversion. This is useful if you want primitive int array instead of List of Integers.

Other utilities

Sub-commands

Many programs split up their functionality into a number of sub-commands, for example, the git program can invoke sub-commands like git stash, git checkout and git commit. Splitting up functionality this way can be a particularly good idea when a program performs several different functions which requires different kinds of command-line arguments. ArgumentParser supports the creation of such sub-commands with the ArgumentParser.addSubparsers() method. ArgumentParser.addSubparsers() method is normally called with no arguments and returns Subparsers object. This object has Subparsers.addParser() method, which takes a command name and returns Subparser object. Subparsers.addParser() method can take prefixChars argument just like prefixChars of ArgumentParsers.newArgumentParser() method. If a version of Subparsers.addParser() method without prefixChars is used, prefixChars is inherited from main parser. Some example usage:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").action(Arguments.storeTrue()).help("foo help");
    Subparsers subparsers = parser.addSubparsers().help("sub-command help");

    Subparser parserA = subparsers.addParser("a").help("a help");
    parserA.addArgument("bar").type(Integer.class).help("bar help");

    Subparser parserB = subparsers.addParser("b").help("b help");
    parserB.addArgument("--baz").choices("X", "Y", "Z").help("baz help");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ java Demo a 12
Namespace(foo=false, bar=12)
$ java Demo --foo b --baz Z
Namespace(baz=Z, foo=true)

Note that the object returned by ArgumentParser.parseArgs() method will only contain attributes for the main parser and the subparser that was selected by the command line (and not any other subparsers). So in the example above, when the a command is specified, only the foo and bar attributes are present, and when the b command is specified, only foo and baz attributes are present. Similarly, when a help message is requested from a subparser, only the help for that particular parser will be printed. The help message will not include parent parser or sibling parser messages (A help message for each subparser command, however, can be given using Subparser.help() method.):

$ java Demo --help
usage: prog [-h] [--foo] {a,b} ...

positional arguments:
  {a,b}                  sub-command help
    a                    a help
    b                    b help

optional arguments:
  -h, --help             show this help message and exit
  --foo                  foo help

$ java Demo a --help
usage: prog a [-h] bar

positional arguments:
  bar                    bar help

optional arguments:
  -h, --help             show this help message and exit

$ java Demo b --help
usage: prog b [-h] [--baz BAZ]

optional arguments:
  -h, --help             show this help message and exit
  --baz BAZ              baz help

Subparsers also has Subparsers.title() method and Subparsers.description() method. When either is present, the subparser's commands will appear in their own group in the help output. For example:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    Subparsers subparsers = parser.addSubparsers()
            .title("subcommands")
            .description("valid subcommands")
            .help("additional help");
    subparsers.addParser("foo");
    subparsers.addParser("bar");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ java Demo -h
usage: prog [-h] {foo,bar} ...

optional arguments:
  -h, --help             show this help message and exit

subcommands:
  valid subcommands

  {foo,bar}              additional help

As you can see above, all sub-commands are printed in help message. It would be good for only 2 or 3 sub-commands, but if there are many sub-commands, the display will become quite ugly. In that case, Subparsers.metavar() method sets text to use instead of all sub-command names. For example:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    Subparsers subparsers = parser.addSubparsers().title("subcommands")
            .description("valid subcommands").help("additional help")
            .metavar("COMMAND");
    subparsers.addParser("foo").help("foo help");
    subparsers.addParser("bar").help("bar help");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
        System.exit(1);
    }
}
$ java Demo -h
usage: prog [-h] COMMAND ...

optional arguments:
  -h, --help             show this help message and exit

subcommands:
  valid subcommands

  COMMAND                additional help
    foo                  foo help
    bar                  bar help

Furthermore, Subparser supports alias names, which allows multiple strings to refer to the same subparser. This example, like svn, aliases co as a shorthand for checkout:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    Subparsers subparsers = parser.addSubparsers();
    Subparser checkout = subparsers.addParser("checkout").aliases("co");
    checkout.addArgument("foo");
    Namespace ns = parser.parseArgsOrFail(args);
    System.out.println(ns);
}
$ java Demo co bar
Namespace(foo=bar)

One particularly effective way of handling sub-commands is to combine the use of Subparser.setDefault() method so that each subparser knows which function it should execute. For example:

private static interface Accumulate {
    int accumulate(Collection<Integer> ints);
}

private static class Sum implements Accumulate {
    @Override
    public int accumulate(Collection<Integer> ints) {
        int sum = 0;
        for (Integer i : ints) {
            sum += i;
        }
        return sum;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName();
    }
}

private static class Max implements Accumulate {
    @Override
    public int accumulate(Collection<Integer> ints) {
        return Collections.max(ints);
    }

    @Override
    public String toString() {
        return getClass().getSimpleName();
    }
}

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    Subparsers subparsers = parser.addSubparsers();
    Subparser parserSum = subparsers.addParser("sum")
            .setDefault("func", new Sum());
    parserSum.addArgument("ints").type(Integer.class).nargs("*");
    Subparser parserMax = subparsers.addParser("max")
            .setDefault("func", new Max());
    parserMax.addArgument("ints").type(Integer.class).nargs("+");
    try {
        Namespace res = parser.parseArgs(args);
        System.out.println(((Accumulate) res.get("func"))
                .accumulate((Collection<Integer>) res.get("ints")));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo  sum 1 3 2
6
$ java Demo  max 1 3 2
3

The alternative way is use Subparsers.dest() method. With this dest value, the selected command name is stored as an attribute:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    Subparsers subparsers = parser.addSubparsers().dest("subparser_name");
    Subparser subparser1 = subparsers.addParser("1");
    subparser1.addArgument("-x");
    Subparser subparser2 = subparsers.addParser("2");
    subparser2.addArgument("y");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo 2 frobble
Namespace(subparser_name=2, y=frobble)

Subparsers allows sub-command names to be abbreviated as long as the abbreviation is unambiguous, just like long options:

enum Command {
    CLONE, CLEAN
};

public static void main(String[] args) {
    ArgumentParser ap = ArgumentParsers.newArgumentParser("prog");
    Subparsers subparsers = ap.addSubparsers();
    subparsers.addParser("clone").setDefault("command", Command.CLONE);
    subparsers.addParser("clean").setDefault("command", Command.CLEAN);
    Namespace res = ap.parseArgsOrFail(args);
    System.out.println(res);
}
$ java Demo clo
Namespace(command=CLONE)
$ java Demo cle
Namespace(command=CLEAN)
$ java Demo cl
usage: prog [-h] {clone,clean} ...
prog: error: ambiguous command: cl could match clean, clone

An error is produced for arguments that could produce more than one sub-commands.

fileType()

The Arguments.fileType() will convert an argument to File object. It has several convenient verification features such as checking readability or existence of a given path. The command-line programs traditionally accept - as standard input. The Arguments.fileType() supports this tradition too. To enable this, just use acceptSystemIn() method:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog")
            .defaultHelp(true);
    parser.addArgument("-i", "--in")
            .type(Arguments.fileType().acceptSystemIn().verifyCanRead())
            .setDefault("-");
    parser.addArgument("-o", "--out").type(Arguments.fileType());
    try {
        Namespace ns = parser.parseArgs(args);
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo -h
usage: prog [-h] [-i IN] [-o OUT]

optional arguments:
  -h, --help             show this help message and exit
  -i IN, --in IN         (default: -)
  -o OUT, --out OUT
$ java Demo -i not-found
usage: prog [-h] [-i IN] [-o OUT]
prog: error: argument -i/--in: Insufficient permissions to read file: 'not-found'

Argument groups

By default, ArgumentParser groups command line arguments into "positional arguments" and "optional arguments" when displaying help messages. When there is a better conceptual grouping of arguments than this default one, appropriate groups can be created using the ArgumentParser.addArgumentGroup():

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    ArgumentGroup group = parser.addArgumentGroup("group");
    group.addArgument("--foo").help("foo help");
    group.addArgument("bar").help("bar help");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo -h
usage: prog [-h] [--foo FOO] bar

positional arguments:

optional arguments:
  -h, --help             show this help message and exit

group:
  --foo FOO              foo help
  bar                    bar help

ArgumentParser.addArgumentGroup() returns ArgumentGroup object which has ArgumentGroup.addArgument() just like a ArgumentParser. When an argument is added to the group, the parser treats it just like a normal argument, but displays the argument in a separate group for help messages. With the title string specified in ArgumentParser.addArgumentGroup() and the description specified in ArgumentGroup.description(), you can customize the help message:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog", false);
    ArgumentGroup group1 = parser.addArgumentGroup("group1")
            .description("group1 description");
    group1.addArgument("foo").help("foo help");
    ArgumentGroup group2 = parser.addArgumentGroup("group2")
            .description("group2 description");
    group2.addArgument("--bar").help("bar help");
    parser.printHelp();
}
$ java Demo
usage: prog [--bar BAR] foo

group1:
  group1 description

  foo                    foo help

group2:
  group2 description

  --bar BAR              bar help

Note that any arguments not in your user defined groups will end up back in the usual "positional arguments" and "optional arguments" sections.

Mutual exclusion

ArgumentParser.addMutuallyExclusiveGroup() creates a mutually exclusive group. ArgumentParser will make sure that only one of the arguments in the mutually exclusive group was present on the command line:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    MutuallyExclusiveGroup group = parser.addMutuallyExclusiveGroup();
    group.addArgument("--foo").action(Arguments.storeTrue());
    group.addArgument("--bar").action(Arguments.storeFalse());
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo --foo
Namespace(foo=true, bar=true)
$ java Demo --foo --bar
usage: prog [-h] [--foo | --bar]
prog: error: argument --bar: not allowed with argument --foo

Specifying true to MutuallyExclusiveGroup.required() indicates that at least one of the mutually exclusive arguments is required:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    MutuallyExclusiveGroup group = parser.addMutuallyExclusiveGroup("group")
            .required(true);
    group.addArgument("--foo").action(Arguments.storeTrue());
    group.addArgument("--bar").action(Arguments.storeFalse());
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo
usage: prog [-h] (--foo | --bar)
prog: error: one of the arguments --foo --bar is required

The MutuallyExclusiveGroup support the title and description just like ArgumentGroup object. If both title and description are not specified, the help message for this group is merged into the other optional arguments. With either or both title and description, the help message is in separate group:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    MutuallyExclusiveGroup group = parser.addMutuallyExclusiveGroup("group");
            .description("group description");
    group.addArgument("--foo").action(Arguments.storeTrue());
    group.addArgument("--bar").action(Arguments.storeFalse());
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo -h
usage: prog [-h] (--foo | --bar)

optional arguments:
  -h, --help             show this help message and exit

group:
  group description

  --foo
  --bar

Parser defaults

Most of the time, the attributes of the object returned by ArgumentParser.parseArgs() will be fully determined by inspecting the command line arguments and the argument actions. ArgumentParser.setDefault() allows some additional attributes that are determined without any inspection of the command line to be added:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("foo").type(Integer.class);
    parser.setDefault("bar", 42).setDefault("baz", "badger");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo 736
Namespace(baz=badger, foo=736, bar=42)

Note that parser-level defaults always override argument-level defaults:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").setDefault("bar");
    parser.setDefault("foo", "spam");
    try {
        System.out.println(parser.parseArgs(args));
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo
Namespace(foo=spam)

Parser-level defaults can be particularly useful when working with multiple parsers. See Sub-commands for an example of this type. ArgumentParser.getDefault() returns the default value for a attribute, as set by either Argument.setDefault() or by ArgumentParser.setDefault():

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newArgumentParser("prog");
    parser.addArgument("--foo").setDefault("badger");
    System.out.println(parser.getDefault("foo"));
}
$ java Demo
badger

Printing help

In most typical applications, ArgumentParser.parseArgs() and ArgumentParser.handleError() will take care of formatting and printing any usage or error messages. However, several formatting methods are available: