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.newFor("prog").build()
                .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

named 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.newFor() static method of ArgumentParsers class. This will return a builder for the parser. (Note: Prior to 0.8.0 an ArgumentParser object was created using newArgumentParser(...) methods of ArgumentParsers. See Migration.) Use method ArgumentParserBuilder.build() to create the parser:

ArgumentParser parser = ArgumentParsers.newFor("prog").build()
.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, use ArgumentParsers.newFor() static method of ArgumentParsers class. This will return a builder for the parser. The following parameter must be specified:

  • prog - The name of the program. This is necessary because main() method in Java does not provide program name.

Configure the parser to be build using methods of the builder:

  • addHelp - Add a -h/--help option to the parser. (default: true).
  • prefixChars - The set of characters that prefix named arguments. (default: '-')
  • fromFilePrefix - The set of characters that prefix file path from which additional arguments are read. (default: null)
  • locale - The locale to use for messages. (default: Locale.getDefault())
  • cjkWidthHack - Treat Unicode characters having East Asian Width property Wide/Full/Ambiguous to have twice a width of ascii characters when formatting help message if locale is "ja", "zh" or "ko". (default: true)
  • defaultFormatWidth - The default width (in columns) for formatting messages. This value is used if terminal width detection is disabled or fails. (default: 75)
  • terminalWidthDetection - Detect the width of the terminal the application is running in. If the terminal width cannot be detected, the default format width is used. (default: true)
  • singleMetavar - Show the metavar string in help message only after the last flag instead of each flag. (default: false)
  • noDestConversionForPositionalArgs - Do not perform any conversion to produce "dest" value from positional argument name. (default: false)

The parser is created using method ArgumentParserBuilder.build().

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.newFor().

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.newFor("prog").build();
    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]

named 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 ArgumentParserBuilder.addHelp():

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

named 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
        .newFor("prog").addHelp(true).prefixChars("+/").build();
    parser.printHelp();
}
$ java Demo
usage: prog [+h]

named 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 ArgumentParserBuilder.prefixChars():

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("prog").prefixChars("-+")
            .build();
    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.

fromFilePrefix

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 fromFilePrefix 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.newFor("prog")
            .fromFilePrefix("@").build();
    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, fromFilePrefix is null, which means no argument is treated as file path.

locale

The locale for messages of ArgumentParser objects can be changed by using ArgumentParserBuilder.locale(). For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("prog")
            .locale(new Locale("nl")).build();
    parser.printHelp();
}
$ java Demo
gebruik: prog [-h]

optionele argumenten:
  -h, --help             toon dit hulpbericht en sluit af

Currently messages have been (partially) translated to Dutch, English, German and Russian.

The default locale is the default locale of the JVM (Locale.getDefault()).

cjkWidthHack

A number of characters in Chinese, Japanese and Korean (CJK) are wider than others. If those characters are treated to have the same width as other characters, texts may extend past the right margin when printed. By enabling the CJK width, 2 columns are used for these wide characters during the determination of line breaks, resulting in better formatted text. To enable or disable handling of wide CJK characters use ArgumentParserBuilder.cjkwidthHack():

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("prog")
            .cjkWidthHack(false).build()
    ...
}

cjkWidthHack is true by default.

defaultFormatWidth

Messages generated by ArgumentParser objects are formatted to fit within a number of columns. ArgumentParserBuilder.defaultFormatWidth() can be used to set the number of columns to use when terminalWidthDetection is disabled or when the detection cannot determine the number of columns from the environment:

public static void main(String[] arguments) {
    ArgumentParser parser = ArgumentParsers.newFor("prog")
            .defaultFormatWidth(40).build()
            .description(
                    "A program showing how argparse4j formats long messages.");
    parser.printHelp();
}
$ java Demo
usage: prog [-h]

A   program   showing   how   argparse4j
formats long messages.

...

The default value for defaultFormatWidth is 75.

terminalWidthDetection

Argparse4j tries to format messages so they fit the terminal the application is running in. It does this by looking at environment variable COLUMNS, or running stty on platforms that support it. The detection can be enabled or disabled using ArgumentParserBuilder.terminalWidthDetection(). When disabling the detection defaultFormatWidth is used as the number of columns:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("prog")
            .terminalWidthDetection(false).build()
            .description(
                    "A program showing how argparse4j formats long messages. " +
                            "Terminal width detection has been disabled, " +
                            "so this description is formatted to 75 characters wide.");
    parser.printHelp();
}
$ java Demo
usage: prog [-h]

A program showing  how  argparse4j  formats  long  messages. Terminal width
detection has  been  disabled,  so  this  description  is  formatted  to 75
characters wide.

...

By default terminalWidthDection is true.

singleMetavar

The metavariable of an argument can be printed after each argument name or only once after all argument names. This behavior is controlled using ArgumentParserBuilder.singleMetavar(). Here is an example using a single metavariable:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("single")
            .singleMetavar(true).build();
    parser.addArgument("-f", "-file").nargs("+").metavar("FILE");
    parser.printHelp();
}
$ java Demo
usage: single [-h] [-f FILE [FILE ...]]

named arguments:
  -h, --help             show this help message and exit
  -f, -file FILE [FILE ...]

Compare this with the output if using multiple metavariables:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("multiple")
            .singleMetavar(false).build();
    parser.addArgument("-f", "-file").nargs("+").metavar("FILE");
    parser.printHelp();
}
$ java Demo
usage: multiple [-h] [-f FILE [FILE ...]]

named arguments:
  -h, --help             show this help message and exit
  -f FILE [FILE ...], -file FILE [FILE ...]

singleMetavar defaults to false, so the metavariable is printed after each argument name.

noDestConversionForPositionalArgs

Prior to 0.5.0 the destination for positional arguments was not automatically determined from the argument name. See Migration. ArgumentParserBuilder.noDestConversionForPositionalArgs() can be used to revert back to the pre 0.5.0 behavior. Note that you must explicitly set a destination when you enable this option, because otherwise the destination will be null:

public static void main(String[] arguments) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("prog")
            .noDestConversionForPositionalArgs(true)
            .build();
    parser.addArgument("foo-bar").dest("explicit-dest");
    System.out.println(parser.parseArgs(arguments));
}
$ java Demo value
Namespace(explicit-dest=value)

By default noDestConversionForPositionalArgs is false, so the names of positional arguments are automatically converted to destinations.

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.newFor("prog").build()
        .description("A foo that bars");
    parser.printHelp();
}
$ java Demo
usage: prog [-h]

A foo that bars

named 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.newFor("prog").build()
            .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

named 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.newFor("prog").build()
        .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])

named 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.newFor("prog").build();
    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

named 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.newFor("prog").build()
            .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

named 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 a named 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, a named 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, named arguments will be identified by the - prefix (or one of prefixChars if it is specified, and the remaining arguments will be assumed to be positional:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newFor("prog").build();
    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.newFor("prog").build();
    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 named arguments that specify sort of flags. For example:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("PROG").build()
        .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.newFor("prog").addHelp(false)
            .build();
    parser.addArgument("--help").action(Arguments.help());
    System.out.println(parser.parseArgs(args));
}
$ java Demo --help
usage: prog [--help]

named 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.newFor("prog").build();
    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.newFor("prog").build();
        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 named 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.newFor("prog").build();
        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.newFor("prog").build();
        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.newFor("prog").build();
        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.newFor("prog").build();
        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 named 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 named 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.newFor("prog").build();
    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.newFor("prog").build();
    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 line argument was not present:

public static void main(String[] args) throws ArgumentParserException {
    ArgumentParser parser = ArgumentParsers.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build()
            .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.newFor("prog").build()
            .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.newFor("prog").build()
            .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.newFor("prog").build();
    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]

named 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}]

named 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}]

named 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.

To use case-insensitive matching of enum value names, use either Arguments.caseInsensitiveEnumType() (uses name()) or Arguments.caseInsensitiveEnumStringType() (uses toString()). Note that Locale.ROOT is used for case-insensitive comparison to ensure that correct parsing of arguments is not dependent on the locale of the parser.

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.newFor("prog").build();
    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.newFor("prog").build();
    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, ",", "{", "}") };
}

The name of types in messages can be localized. Names for the primitive types (and their wrappers) are provided. Names for custom types are looked up using the following methods. The first name that is found is returned:

  1. The key displayName is looked up in resource bundle <fully-qualified type name>-argparse4j. For examaple: Resource bundle com/example/CustomType-argparse4j*.properties is used for com.example.CustomType.
  2. The simple name of the class of the type prepended with type. is used as a key to look up the name in the resource bundle of argparse4j. This method provides the names for primitive type wrappers. For example: The key type.Integer is used for java.lang.Integer.
  3. The simple name of the class of the custom type.

Note that if your custom type has the same simple name as a wrapper for a primitive type, the localized name of that wrapper will also be used for your custom type.

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.newFor("prog").build();
    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.newFor("prog").build();
    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 named 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.newFor("prog").build();
    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.newFor("prog").build();
    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

named 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.newFor("prog").build();
    parser.addArgument("--foo").help(Arguments.SUPPRESS);
    try {
        Namespace ns = parser.parseArgs(args);
    } catch (ArgumentParserException e) {
        parser.handleError(e);
    }
}
$ java Demo -h
usage: prog [-h]

named 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 named arguments, the dest value is uppercased. So, a single positional argument with dest("bar") will be referred to as bar. A single named 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.newFor("prog").build();
    parser.addArgument("--foo");
    parser.addArgument("bar");
    parser.printHelp();
}
$ java Demo
usage: prog [-h] [--foo FOO] bar

positional arguments:
  bar

named 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.newFor("prog").build();
    parser.addArgument("--foo").metavar("YY");
    parser.addArgument("bar").metavar("XX");
    parser.printHelp();
}
$ java Demo
usage: prog [-h] [--foo YY] XX

positional arguments:
  XX

named 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.newFor("prog").build();
    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]

named 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.newFor("prog").build();
    parser.addArgument("bar");
    parser.addArgument("foo-bar");
    System.out.println(parser.parseArgs(args));
}
$ java Demo XX YY
Namespace(bar=XX, foo_bar=YY)

For named 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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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 (32 bits)
$ 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.newFor("prog").build();
    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.newFor("prog").build();
    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, 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.newFor("prog").build();
    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.newFor("prog").build();
    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. 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.newFor("prog").build();
    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

named 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

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

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

named 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.newFor("prog").build();
    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} ...

named 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.newFor("prog").build();
    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 ...

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

subcommands:
  valid subcommands

  COMMAND                additional help
    foo                  foo help
    bar                  bar help

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

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

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

subcommands:
  valid subcommands

  {foo}                  additional 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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build()
            .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]

named 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'

The verifications can be used in any combination, but not all combinations make sense. The verifications can be split in 2 categories: presence & type, and permissions & properties. You should always use exactly 1 verification from the presence & type category, and then you can use 0 or more permission & property verifications:

Permission/property Does not exist Exists Is file Is directory
Is absolute
Read  
Write  
Execute  
Write parent
Create      

From version 0.8.0 it is also possible to specify verification groups, of which 1 must verify successfully. This is useful where you can create the needed file or directory yourself if it does not exist yet. For example:

<file argument type>
        // The output directory does not exist, but it is possible to create it.
        .verifyNotExists().verifyCanCreate()
        .or()
        // The output directory already exists, and it is possible to write to it.
        .verifyIsDirectory().verifyCanWrite()

Argument groups

By default, ArgumentParser groups command line arguments into "positional arguments" and "named 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.newFor("prog").build();
    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:

named 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.newFor("prog")
            .addHelp(false).build();
    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 "named 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.newFor("prog").build();
    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.newFor("prog").build();
    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 named arguments. With either or both title and description, the help message is in separate group:

public static void main(String[] args) {
    ArgumentParser parser = ArgumentParsers.newFor("prog").build();
    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)

named 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.newFor("prog").build();
    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.newFor("prog").build();
    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.newFor("prog").build();
    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:

Extensions

Java 7

Argument types for classes and interfaces introduced in Java 7 are available in module argparse4j-java7. The following argument types are available:

java.nio.file.Path
Argument type: net.sourceforge.argparse4j.ext.java7.PathArgumentType. The no-arg constructor used the default file system. If you want to resolve paths for another file system, use the constructor accepting a file system. Note that using the non-default file system disables all file verification checks.

Hadoop

Argument types for classes and interfaces of Hadoop are available in module argparse4j-hadoop. The following argument types are available:

org.apache.hadoop.fs.Path
Argument type: net.sourceforge.argparse4j.ext.hadoop.PathArgumentType.