Implement custom option handler in args4j

In the previous post about args4j, I showed how to write a custom multi-value option handler based on a built-in handlers.

This post guides you through writing your own option/argument handler. I’m going to show you an example of a handler that sets a java.time.Duration option.

First of all, you have to decide which base class to extend: either OptionHander or OneArgumentOptionHandler. I preferred the latter one, because it can be used for multi-value options (with a DelimitedOptionHandler). In both cases you must implement a ‘boilerplate’ constructor that delegates to the superclass. Here is the stub of the handler:

public class SimplifiedDurationHandler extends OneArgumentOptionHandler<Duration> {
    public SimplifiedDurationHandler(CmdLineParser parser, OptionDef option, Setter<? super Duration> setter) {
        super(parser, option, setter);

    protected Duration parse(String argument) throws CmdLineException {
        // ...

The next step is to implement the actual parse method. Extending the OneArgumentOptionHandler gives another advantage. You don’t have to deal with Setters. You just return the parsed value and the base class will set the option.

In my example, I’m going to match the argument against a regular expression. In case of a successful match, I create a Duration from the amount and unit parts. In case of a mis-match, I signal the error to the library by throwing a CmdlineException:

protected Duration parse(String argument) throws CmdLineException {
    Matcher matcher = PATTERN.matcher(argument);
    if (!matcher.matches()) {
        throw misformattedArgumentException(argument);
    return Duration.of(Integer.valueOf(amount(matcher)), unit(matcher));

private CmdLineException misformattedArgumentException(String token) {
    return new CmdLineException(owner, Messages.ILLEGAL_OPERAND, option.toString(), token);

By passing a Messages.ILLEGAL_OPERAND and option.toString() to the CmdLineException constructor, you’ll get a nice error message:

"1h" is not a valid value for "-d (--duration)"

for an @Option, or:

"1h" is not a valid value for "duration"

for an @Argument.

You can see the full source code together with an integration test on Github:

Multi-value option handler in args4j

If you are building a command-line app and you want to pass multiple values in a single option, there is a built-it support for that in args4j.

The only thing you have to do is to extend org.kohsuke.args4j.spi.DelimitedOptionHandler, passing the delimiter ("," in the example below) and the single-value option handler (IntOptionHandler).

public class MultiIntOptionHandler extends DelimitedOptionHandler<Integer> {
    public MultiIntOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Integer> setter) {
        super(parser, option, setter, ",", new IntOptionHandler(parser, option, setter));

The usage is straightforward:

@Option(name = "-e", aliases = "--elapse", usage = "elapses in", handler = MultiIntOptionHandler.class)
private List<Integer> elapsesIn = new ArrayList<>();