CmdOption

CmdOption is a simple annotation-driven command line parser toolkit for Java 5 applications that is configured through annotations.

Current version is CmdOption 0.3.2.

Or see Release History.

Overview

CmdOption is a simple annotation-driven command line parser toolkit for Java 5 applications. Everything you need is (at least one) simple configuration object. Each field and method annotated with an CmdOption annotation will be processed. Based on this config, CmdOption is able to parse any commandline, guaranteeing the declared specification. The result is directly stored in the given config object. When errors occur, CmdOption gives a meaningful error message. Generated output and validation/error messages can be localized.

Download

Download the latest version CmdOption 0.3.2.

CmdOption is also available via Maven central repository.

Maven users can use the following dependency declaration:

1<dependency>
2    <groupId>de.tototec</groupId>
3    <artifactId>de.tototec.cmdoption</artifactId>
4    <version>0.3.2</version>
5</dependency>

SBuild users can use the following dependency:

1"mvn:de.tototec:de.tototec.cmdoption:0.3.2" 

Example

A simple config class could look like this:

 1public class Config {
 2  @CmdOption(names = {"--verbose", "-v"}, description = "Be more verbose")
 3  private boolean verbose;
 4
 5  @CmdOption(names = {"--options", "-o"}, args = {"name", "value"}, maxCount = -1, description = "Additional options when processing names")
 6  private final Map<String, String> options = new LinkedHashMap<String, String>();
 7
 8  @CmdOption(args = {"file"}, description = "Names to process", minCount = 1, maxCount = -1)
 9  private final List<String> names = new LinkedList<String>();
10}

For a more complete example see also the translation example and also visit the Examples page.

The commandline based on the config object above can contain:
  • an optional "--verbose" or "-v" option
  • any count of additional option pairs via "--options" or "-o"
  • at least on paramter

Parsing the command line is as easy as the following three lines:

1Config config = new Config();
2CmdlineParser cp = new CmdlineParser(config);
3cp.parse(new String[] {"-v", "name1", "name2"});
4
5assert config.verbose;
6assert config.names.length() == 2;
7assert config.options.isEmpty();

Options and Parameters

The @CmdOption annotation can be used to declare fields and methods as options.

Attributes of the @CmdOption annotation:
  • names : String[] - The names of this option.
  • description : String - The description of the option.
  • args : String - The arguments (their names) supported by this option. The count of arguments is used, to determite the option handler to use. The names are used in (validation) messages and the usage display.
  • minCount : int - The minimal allowed count this option can be specified. Optional options have 0 here, which is the default.
  • maxCount : int - The maximal allowed count this option can be specified. Use -1 to specify infinity. Default is 1.
  • handler : Class - A class implementing the CmdOptionHandler interface to apply the parsed option to the annotated field or method. If this is not given, all handler registered for auto-detect will by tried in order.
  • isHelp : boolean - Special marker, that this option is a help request. Typically, such an option is used to display a usage information to the user and exit. If such an option is parsed, validation will be disabled to allow help request even when the command line is incorrect.
  • hidden : boolean - If true, do not show this option in the usage.
  • requires : String[] - If this option is only valid in conjunction with other options, those required options should be declared here. (Since 0.2.0)
  • conflictsWith : String[] - If this option can not be used in conjunction with an specific other option, those conflicting options should be declared here. (Since 0.2.0)

If a @CmdOption annotation without any names attribute is found, this option is treated as main parameter(s) of the command line interface. At most one field or method can be annotated as such. The main parameter option gets all command line arguments that are not parsed into any other option or command.

Commands

CmdOption also supports the notion of commands. At most one command can be selected and supports itself options and main parameters. The @CmdCommand annotation can be used for classes.

Examples for tools that have command-style command line interfaces: subversion, git, mdadm, emerge/portage, SBuild, cmvn, ...

Attributes of the @CmdCommand annotation:
  • names: String[] - The names of this command.
  • description: String - The description of the command.
  • hidden: boolean - If true, do not show this command in the usage.

When a command is parsed, all succeeding arguments are parsed into that command (its options, and parameter). It is possible, to have options with the same name in different commands or in a command and the main program. The position of that option decides, which handler is invoked: before the command it is treated as a main options, after the command, its treated as an option of that command. If the main program support main parameters and also has commands, than the main parameters must be given before the command starts.

You can access the parsed command through the methods getParsedCommandName() or getParsedCommandObject() of class CmdlineParser.

It is possible, to define a default command, that is implicitly assumed when the user does not use a command explicitly. When the commandline parser detects an else unknown option or parameter it will try to parse the rest of the command line as if the default command was issued. You can set the default commend with setDefaultCommandName() or setDefaultCommandClass() of class CmdlineParser.

Composition

The command line parser supports more that one config object. Each object annotated with @CmdCommand is treated as command, all other can contain options for the main program.

To use the same class (or even object) for common or shared options, e.g. to add a --verbose option to all commands, you can annotate the relevant field with @CmdOptionDelegate.

Localization

There are two source of messages, that needs localization. Those from CmdOption itself like error and validation messages, and those, provided by the user of the CmdOption toolkit.

Localized CmdOption output

CmdOption itself supports localized output. The JVM default locale (country, language, variant) is used.

Currently, CmdOption comes with the following languages:
  • English
  • German

If you want to translate CmdOption into another language, we apreciate your contribution! See HowToProvideTranslations for details.

Localized options and descriptions

CmdOption also supports the translation of the user-provided strings. Those strings are:
  • The AboutLine
  • The option descriptions
  • The command descriptions

If you provide a ResourceBundle, CmdOption will use that bundle to translate your messages. The JVM default locale is used.

You can either create the ResourceBundle yourself and set it into the CmdlineParser, or you can tell the CmdlineParser the name for the message catalog and the classloader, that should be used to access the message catalog.

Example: A translation via Properties file

File: org/example/Main.java

 1package org.example;
 2
 3import java.util.*;
 4import de.tototec.cmdoption.*;
 5
 6public class Main {
 7
 8  public static class Config {
 9    @CmdOption(names = {"--help", "-h"}, description = "Show this help.", isHelp = true)
10    public boolean help;
11
12    @CmdOption(names = {"--verbose", "-v"}, description = "Be more verbose.")
13    private boolean verbose;
14
15    @CmdOption(names = {"--options", "-o"}, args = {"name", "value"}, maxCount = -1,
16      description = "Additional options when processing names.")
17    private final Map<String, String> options = new LinkedHashMap<String, String>();
18
19    @CmdOption(args = {"file"}, description = "Names to process.", minCount = 1, maxCount = -1)
20    private final List<String> names = new LinkedList<String>();
21  }
22
23  public static void main(String[] args) {
24    Config config = new Config();
25    CmdlineParser cp = new CmdlineParser(config);
26    cp.setResourceBundle(Main.class.getPackage().getName() + ".Messages", Main.class.getClassLoader());
27    cp.setProgramName("myprogram");
28    cp.setAboutLine("Example names processor v1.0");
29
30    try {
31      cp.parse(args);
32    } catch (CmdlineParserException e) {
33      System.err.println("Error: " + e.getLocalizedMessage() + "\nRun myprogram --help for help.");
34      System.exit(1);
35    }
36
37    if (config.help) {
38      cp.usage();
39      System.exit(0);
40    }
41
42    // ...
43  }
44}

We will use a properties files to provide the translations into German.

File: org/example/Messages_de.properties

Show\ this\ help.=Zeigt diese Hilfe an.
Be\ more\ verbose.=Sei ausf\u00fchrlicher.
Additional\ options\ when\ processing\ names=Zus\u00e4tzliche Optionen bei der Namensverarbeitung.
Names\ to\ process=Zu verarbeitende Namen.
Example\ names\ processor\ v1.0=Beispiel Namensprozessor v1.0
name=Name
value=Wert

Output of the program without any locale:

% LC_ALL=C java -jar myprogram --help
Example names processor v1.0

Usage: myprogram [options] [parameter]

Options:
  --help,-h                Show this help.
  --options,-o name value  Additional options when processing names.
  --verbose,-v             Be more verbose.

Parameter:
  file  Names to process.

Output of the program in a German environment:

% java -jar myprogram --help
Beispiel Namensprozessor v1.0

Aufruf: myprogram [Optionen] [Parameter]

Optionen:
  --help,-h                Zeigt diese Hilfe an.
  --options,-o Name Wert   Zusätzliche Optionen bei der Namensverarbeitung.
  --verbose,-v             Sei ausführlicher.

Parameter:
  file  Zu verarbeitende Namen.

CmdOptionHandler

CmdOption supports field and method access. The set of supported types and method signatures is not hardcoded, but determined by the registered CmdOptionHandlers. CmdOptions comes with some ready-to-use CmdOptionsHandlers. By default, a well-choosen set of CmdOptionsHandlers is already registered, making a good start for most usage scenarios. To customize the behavoir of CmdOption, one has some options:

  • Write and register additional CmdOptionHandlers
  • if necessary, unregister all handlers before registering
  • Explicitly select a specific CmdOptionHandler in the @CmdOption-Annotation

Registering an additional CmdOptionHandler

1CmdlineParser cp = new CmdlineParser(config);
2cp.registerHandler(new MyOptionHandler());

The order of registered handlers is important. The first handler, that will match a declared field or method, will be used to parse it. To explicitly force a specific handler, use the @CmdOption(handler = TheSpecificHandler.class).

Pre-registered CmdOptionHandlers

At construction time CmdlineParser pre-registeres various handlers like the following snippet:

1CmdlineParser cp = new CmdlineParser(config);
2cp.registerHandler(new BooleanOptionHandler());
3cp.registerHandler(new BooleanHandler());
4cp.registerHandler(new StringFieldHandler());
5cp.registerHandler(new PutIntoMapHandler());
6cp.registerHandler(new AddToCollectionHandler());
7cp.registerHandler(new StringMethodHandler());
8cp.registerHandler(new IntegerHandler());

Unregistering all registered CmdOptionHandlers

1CmdlineParser cp = new CmdlineParser(config);
2cp.unregisterAllHandler();

Debugging

CmdOption has a fairly detailed set of error messages, that will be thrown as CmdlineParserException. If you need more information what goes on under the hood, you can use the special command line option --CMDOPTION_DEBUG. When used, CmdOption will display detailed information about the found configurations and the parsing process. This might help to understand issues further. I most cases, this will help you to resolve your issues. Of course, you can disable this functionality with setDebugModeAllowed(false).

If you have issues you can not solve, do not hessitate to open a support ticket or search for other (open) issues in the CmdOption ticket system.

Creating a streaming command line interface

Normally, CmdOption parses a complete command line, populates the config object(s) and ensures, that the config is valid, according to the configuration. Only, if the config is checked and ok, the parse method returns.

In some cases, a streaming command line interface is more appropriate than the typical static approach. In a streaming command line interface each option and parameter is immediatly evaluated before the next option or parameter is read. The next allowed option/parameter often depends on the previously parsed one. An example for an program with a streaming command line interface is ogmtools/ogmmerge.

Creating such a streaming command line parsers is very easy with CmdOption. Of course, most context sensitive validation must be handled by the application itself. You have to add the @CmdOption annotation to methods instead of fields. The arguments of that options, if any, must match the arguments of that method. In the body of such a method the option can now immediatly processed. Typically, minCount and maxCount of the options are unconstrained, as the validity is dependent on the context.