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); } @Override 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 Setter
s. 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
:
@Override 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: