Wednesday, August 9, 2017

Java Command-Line Interfaces (Part 11): CmdLn

This post describes using Ostermiller Java Utilities 1.08.02's CmdLn (Java Command Line Parser) to process command-line arguments from Java-based applications. The Ostermiller Java Utilities include several different types of utilities, but the focus of this post is on the "Command Line Parser" that is described on the components page, "Handle options and arguments to Java command line programs."

The Ostermiller Utilities command line parser does not use annotations, but instead employs the programmatic builder with fluent API concept that some of the other Java-based command-line parsing libraries have also used instead of annotations. The classes com.Ostermiller.util.CmdLn and com.Ostermiller.util.CmdLnOption are used together in the "definition" stage of command-line processing with CmdLn. This is demonstrated in the next code listing.

"Definition" Stage of CmdLn Processing

public static void main(final String[] arguments)
{
   final CmdLn cmdLn
      = new CmdLn(arguments).setDescription("Demonstrates CmdLn")
         .addOptions(new CmdLnOption[]{
            new CmdLnOption("help",'h'),
            new CmdLnOption("file",'f')
               .setRequiredArgument()
               .setArgumentBounds(1, 1)
               .setDescription("Path and name of file"),
            new CmdLnOption("verbose", 'v')
               .setOptionalArgument()
               .setArgumentBounds(0, 0)
               .setDescription("Enable verbosity")
         });

In the just-shown code listing, three option are defined. One option is a "help" option and the other two options (-h/--help and -v/--verbose) are those used in the other posts in this series on command-line parsing in Java. The code demonstrates that a description can be set for each option for usage/help information and it is possible to designate whether each option is required or optional. The setArgumentBounds(int,int) method is used to specify the minimum and number of arguments that are expected for each option. The file option should always have one and only one argument (the file's path and name), so its minimum and maximum are both 1. The verbosity option should have no arguments (its presence means verbosity is enabled), so its minimum and maximum number of arguments are both 0.

The Ostermiller Java Utilities command line parser provides three approaches for "defining" what's to be parsed. The approach shown above is called the "Options by Name" approach on the CmdLn page. That pages also demonstrates defining the command line options to be parsed with the "Option Enum" and "Call Back to Listeners" approaches (not demonstrated in this post).

Normally in my posts on command-line parsing with Java-based libraries, I introduce how to implement the "parsing" stage after introducing how to implement the "definition" stage. However, with Ostermiller Utilities command line parser, the "parsing" stage is implicit and so I'll return to it after first covering the "interrogation" stage.

The "interrogation" stage is implemented by calling one of the overloaded getResult() methods on the CmdLn instance. If the overloaded getResult(-) method returns null, the option was not present (or not found during parsing). If that overloaded method returns a non-null value, that value will be of type CmdLnResult and represents a parsed option. That returned instance of CmdLnResult provides methods for accessing the argument or arguments associated with the option (such as accessing the path and file name of the -f/--file option in my example). This "interrogation" is demonstrated in the next code listing.

"Interrogation" Stage with CmdLn

if(cmdLn.getResult('h') != null)
{
   cmdLn.printHelp();
   System.exit(0);
}

String fileName = null;
if(cmdLn.getResult('f') != null)
{
   fileName = cmdLn.getResult('f').getArgument();
}
else
{
   out.println("Required parameter -f|--file not provided.\n" + cmdLn.getHelp());
   System.exit(-1);
}

boolean verbose = false;
if (cmdLn.getResult('v') != null)
{
   verbose = true;
}
out.println("File path/name is " + fileName + " and verbosity is set to " + verbose);

The CmdLn class also has getResults methods that return a List<CmdLnResult> to access multiple parsed options. The examples above demonstrate checking the results of the getResult() method call for null to determine whether an option is set or not. The full source code of the Java application used for this post is available on GitHub and uses CmdLn.present(char) instead of null checks for determining presence of an option. The differences can be seen here.

The Ostermiller Java Utilities command line parser does not require an explicit "parsing" call. Instead, the "interrogation" methods previously discussed (overloaded versions of getResult and getResults) implicitly parse when called. Each of these methods calls the public method CmdLn.parse(), but parsing actually only occurs on the first one called because the instance parses a boolean value that tells that instance it does not need to parse again on subsequent calls to getResult or getResults methods.

The next three screen snapshots demonstrate use of this simple Java application using Ostermiller Java Utilities command line parser. The first image depicts the output when no arguments (including the required file path/name argument) are specified. The second image depicts the help/usage output generated when the --help or -h option is specified and shows that there is no error message about the missing parameter in this case. The third screen snapshot demonstrates "happy path" execution of the simple application using the short and long forms of the file and verbosity options.

Here are some additional characteristics of Ostermiller Java Utilities CmdLn to consider when selecting a framework or library to help with command-line parsing in Java.

  • The Ostermiller Java Utilities that CmdLn is a part of are open source and the OstermillerUtils License is the GNU General Public License version 2 (GPL). The com.Ostermiller.util License FAQ explains why the GPL was chosen and the desire to avoid having these libraries "be used in closed source applications."
  • CmdLn is part of the greater Ostermiller Java Utilities, which is available as a single JAR. The ostermillerutils-1.08.02.jar is approximately 272 KB in size and no third-party JARs are needed (no other external dependencies).
  • The Ostermiller Java Utilities requires J2SE 5 or later.
  • The Ostermiller Java Utilities have not seen updates in recent years, but the Version History details the long-term availability of these utilities.

The command line parser portion of the Ostermiller Java Utilities is easy enough to use for basic command-line parsing and gets the job done. However, the Ostermiller Java Utilities have a more restrictive license than most of the open source Java-based command-line processing libraries discussed in this series. Also, one needs to include the entire Ostermiller Java Utilities JAR to get command-line processing functionality and that may feel a bit heavy for some simple command-line-driven applications. I believe that the command line parsing utility provided by Ostermiller Java Utilities will be most attractive to developers whose applications already use the Ostermiller Java Utilities for other utilities it provides.

Additional References

Monday, August 7, 2017

Java Command-Line Interfaces (Part 10): picocli

The main picocli page describes picocli as "a mighty tiny command line interface" that "is a one-file Java framework for parsing command line arguments and generating polished, easily tailored usage help messages. With colors." This post provides a brief overview of applying Picocli 0.9.7 to process command line arguments in Java code.

Like the other Java-based command line processing libraries covered in this series, picocli is open source. Because all of picocli's implementation exists in a single Java source code file, it's easy to use the source directly if desired. The picocli page emphasizes this, "A distinguishing feature of picocli is how it aims to let users run picocli-based applications without requiring picocli as an external dependency: all the source code lives in a single file, to encourage application authors to include it in source form." If you'd rather use picocli as a library, there is a JAR available on the Maven Repository with the numerous compiled .class files (Picocli features one Java file but with numerous nested classes and annotations).

The easiest approach for getting an idea of Picocli's single-file nature is to look at that single file itself. The Java source code for CommandLine.java is available on the Picocli 'download' page. The next two screen snapshots show some output from javap when executed against the CommandLine class and when executed against one its inner annotations and one of its inner classes.

Whether one compiles CommandLine.java into one's own class/JAR file or one chooses to use a pre-built JAR from Maven, the source code of an application using Picocli is obviously the same. The "definition" stage of parsing with Picocli is accomplished by annotating instance fields that will store values associated with command-line options. This is demonstrated in the code snippet below.

"Definition" Stage with Picocli

/**
 * Demonstrate Java-based command-line processing with picocli.
 */
@Command(
   name="Main",
   description="Demonstrating picocli",
   headerHeading="Demonstration Usage:%n%n")
public class Main
{
   @Option(names={"-v", "--verbose"}, description="Verbose output?")
   private boolean verbose;

   @Option(names={"-f", "--file"}, description="Path and name of file", required=true)
   private String fileName;

   @Option(names={"-h", "--help"}, description="Display help/usage.", help=true)
   boolean help;

The code sample just shown demonstrates that Picocli allows for multiple names of the option flags to be specified (I specified single-hyphen single-character names and double hyphen multi-character names in my example). The example also shows that required=true can be specified for required options and help=true can be specified for "help" options that support special help-specific behaviors such as printing usage details and avoiding errors related to absent required options. Note that Picocli 0.9.8 adds more specific help type support with versionHelp and usageHelp.

The "parsing" stage is accomplished in Picocli with CommandLine.populateCommand(T, String...), where the T is the instance of the class with Picocli-annotated fields and the remaining Strings are the arguments to be parsed. This is demonstrated in the next code snippet.

"Parsing" Stage with Picocli

final Main main = CommandLine.populateCommand(new Main(), arguments);

The "interrogation" stage with Picocli consists simply of accessing the Picocli-annotated fields of the instance passed to the CommandLine.populateCommand(T,String...) method in the "parsing" stage. A simple example of this "interrogation" is depicted in the next code listing.

"Interrogation" Stage with Picocli

out.println(
     "The provided file path and name is " + main.fileName
   + " and verbosity is set to " + main.verbose);

To display help/usage information to the user when -h or --help is provided on the command line, it's as simple as "interrogating" the Picocli-annotated field that was designated help=true to see if that boolean is set or not and, if it is set, calling one of the overloaded CommandLine.usage methods. I happened to use one of the static versions of this method as shown in the next code listing.

Help/Usage with Picocli

if (main.help)
{
   CommandLine.usage(main, out, CommandLine.Help.Ansi.AUTO);
}

The next few screen snapshots demonstrate the simple Picocli-based processing application in action. The first image shows the type of error message and stack trace presented when a required flag is not present. The second image shows how the long and short names I specified in the annotations are respected. The third image shows the help feature in action.

One of Picocli's optional features that many of the other Java-based command-line parsing libraries don't have is color syntax support. The first code listing in this post showed some strings defined in annotations with @| |@ syntax. In the screen snapshot demonstrating "help" usage above, these characters were passed through as-is with no special treatment. However, if I instead run this sample code in Cygwin, I see what those tokens accomplish.

From the above screen snapshot, we see that Picocli applied some color syntax (yellow and white) automatically to the individual options' help and that it also applied the customized bold and underlined bold syntax to help description areas where the @| |@ syntax was applied.

Here are some additional characteristics of Picocli to consider when selecting a framework or library to help with command-line parsing in Java.

  • Picocli is open source and is licensed under the Apache License 2.0.
  • Picocli does not require any third-party libraries or frameworks to be downloaded.
    • Picocli source code is completely contained within a single .java file and that source can be copied and pasted into one's own configuration management system and built with the rest of the application code, meaning that even a Picocli JAR file is not strictly necessary.
  • The CommandLine.java source code file (Picocli 0.9.7) is just under 3700 lines (including white space and comments) and is almost 200 KB in size. The picocli-0.9.7.jar file is approximately 83 KB in size.
  • Picocli enjoys current and frequent support. Its 0.9.8 version was released yesterday (after I had written most of this post).
  • Picocli documentation is detailed and in many ways more modern-feeling than the documentation for several other Java-based command-line processing libraries.
  • Picocli support for color syntax is easy to use and support for color syntax on different platforms is documented under the "Supported Platforms" section of the documentation.
  • Picocli's use of annotations on instance-level fields in similar to some of the other Java-based command-line processing libraries and enjoys the same advantages.
  • Basic Picocli features are highly approachable and easy to learn quickly, but Picocli also supports the ability to significantly customize several aspects of command-line processing with Picocli.

The code listings shown in this post are available in complete form on GitHub.

Picocli is a currently supported and updated library for processing command line arguments from Java. It features several of the newer features and approaches of some of the other available Java-based command-line processing libraries and throws in a couple differentiating features (color syntax and entire library encapsulated in single Java source file). Picocli is easy enough to use and appealing in its own right, but is most likely to separate itself from others in a particular developer's opinion if that developer desires the color syntax support or the ability to drop the source code file into the developer's project without any need for a JAR or compiled .class file.

Additional References

Monday, July 24, 2017

Java Command-Line Interfaces (Part 9): parse-cmd

The parse-cmd library consists of a single class, ParseCmd.java, that is "a Java-class used to define and parse command-line parameters in a Java application." The library is hosted on Google Code Archive and so could go away at any time. The JAR also appears to be available on GitHub. This post covers use of parse-cmd 0.0.93 to process command line arguments in Java.

The parse-cmd Requirement Wiki lists several alternatives for processing command line arguments in Java, including some which have been covered previously in this series. After listing these alternatives, it states, "Reviewing these and other entries, it was time to try another parser." The document then goes on to delineate requirements that parse-cmd seeks to satisfy.

The "definition" stage of parsing command-line arguments with parse-cmd is demonstrated in the next (incomplete) code listing. [Note that the example in this post is similar to that used in the previous eight posts in this series.]

"Definition" Stage with parse-cmd

/** String displayed where there is a problem processing arguments. */
private final static String USAGE =
   "java examples.dustin.commandline.parsecmd.Main --file <filePathAndName> [--verbose 1]";

public static void main(final String[] arguments)
{
   final ParseCmd parseCmd
      = new ParseCmd.Builder().parm("--file", "")
                              .req()
                              .parm("--verbose", "0")
                              .help(USAGE)
                              .build();

The code listing demonstrates the definition of the expected command-line parameters using the ParseCmd.Builder() and the fluent methods available on instances of that class. Each method in turn returns an instance of the same Builder class so that these method calls can be chained together as shown above. As shown above, the usage/help string is built manually and provided to the Builder via the help(String) method rather than being built automatically by parse-cmd.

The parm method of the ParseCmd.Builder class is overloaded, but in this code listing I used the method parm(String, String) that accepts the name of the parameter and a "default" value for that parameter. Had I only provided one string to the method accepting just one string, the default would have been assumed to be "1" for that parameter. In the case of the file path and name argument, this can lead parse-cmd to assuming the wrong type of parameter. By providing an empty String explicitly as a default, parse-cmd is able to accurately treat the argument for file path and name as a variable-length string.

The --verbose argument is also defined in the above code and a default value is also provided to it because the implicit default of "1" would have turned verbosity "on" when no argument was provided and that's not been the default for verbosity in any of the earlier posts in this series of command-line parsing with Java.

The invocation of req() on one of the chained returned instances of Builder indicates that the previously defined argument (--file) is required. The other argument (--verbose) does not have this specified and so is implicitly defaulted to optional.

As far as I can tell, there's no easy approach with parse-cmd to specifying an alias or synonym for the defined command-line arguments. In other words, I don't see a way to tell parse-cmd that --file and -f are the same command-line argument. Therefore, I only use the "long" version with double hyphens in this example for both arguments --file and --verbose.

With the previous Java-based command-line parsing libraries covered in this series, the "parsing" stage immediately follows the "definition" stage. While it's possible to make this same transition with parse-cmd, the advertised and preferred approach is to implement the "validation" stage after the "definition" stage and before the "parsing" stage. This stage allows one to see if any errors were found during validation of the available command line arguments and is demonstrated in the next (incomplete) code listing.

"Validation" Stage with parse-cmd

final String errorString = parseCmd.validate(arguments);
if (!errorString.isEmpty())
{
   out.println("ERROR: " + errorString);
}

The code listing just shown demonstrates use of the ParseCmd.validate(String[]) method used to validate that the command-line arguments match those expected as defined in the "definition" stage. If there are any unexpected results, a non-empty String is returned. An empty String is considered a good thing and indicates "valid" command-line arguments.

With valid arguments, one can next move to "parsing" those command-line arguments as demonstrated in the next single-line code listing.

"Parsing" Stage with parse-cmd

final Map<String, String> parsedArguments = parseCmd.parse(arguments);

The result of the invocation of ParseCmd.parse(String[]) is a Java Map<String, String> of argument name to argument value.

The "interrogation" stage with parse-cmd is implemented by simply accessing the Map<String, String> returned by the parsing stage. One can query the map's keys by the argument name and the returned value is the value associated with that argument name. Note that the implication is that all arguments, even "boolean" arguments like --verbose, have a value associated with them rather than the presence or absence of the flag being the only required thing. In other words, --verbose must be followed by a value when expressed on the command line. The interrogation in this case of the two expected arguments is demonstrated in the next code listing.

"Interrogation" Stage with parse-cmd

final Map<String, String> parsedArguments = parseCmd.parse(arguments);
final String filePathAndName = parsedArguments.get("--file");
   out.println("The path/name of the file is '" + filePathAndName
      + "' and verbosity is set to '" + parsedArguments.get("--verbose") + "'.");

The full code listing for the example whose snippets have been shown in this post is available on GitHub.

The next screen snapshot demonstrates a message printed when a required command-line argument (--file) is not provided.

The screen snapshot that follows demonstrates successful application of the parse-cmd based command line processing of the --file and --verbose command line arguments.

Here are some additional characteristics of parse-cmd to consider when selecting a framework or library to help with command-line parsing in Java.

  • parse-cmd is open source with an Apache License 2.0.
  • parse-cmd is hosted on The Google Code Archive, which could be "turned down" at any time (currently states, "which will be turned down in early 2016").
  • The parsecmd-0.0.93.jar JAR file is approximately 50 KB in size.
  • parse-cmd employs a fluent Builder implementation instead of using annotations.

parse-cmd is another library (currently) available for Java developers who need to process command line arguments. It uses some assumptions and implications to make some of its decisions. The author of parse-cmd has written that parse-cmd was written despite "several Java-based command-line parsing solutions [being] available" because "they are generally complex to learn and use."

Additional References

Monday, July 17, 2017

Java Command-Line Interfaces (Part 8): Argparse4j

Argparse4j is a "Java command-line argument parser library" that its main page describes as "a command line argument parser library for Java based on Python's argparse module." In this post, I will look briefly at using Argparse4j 0.7.0 to process command-line arguments similar to those parsed in the seven earlier posts in this series on command-line processing in Java.

The arguments "definition" stage of command-line processing with Argparse4j can be accomplished via the ArgumentParser interface and its addArgument(String...) method. The return type of the addArgument(String...) method is an instance of the Argument interface. Implementations of that interface (usually ArgumentImpl) provide methods for setting the characteristics of each argument. Because each of these methods returns an instance of Argument, these calls can be chained together in a highly fluent manner. This is demonstrated in the next screen snapshot.

"Definition" Stage with Argparse4j

final ArgumentParser argumentParser =
   ArgumentParsers.newArgumentParser("Main", true);
argumentParser.addArgument("-f", "--file")
              .dest("file")
              .required(true)
              .help("Path and name of file");
argumentParser.addArgument("-v", "--verbose")
              .dest("verbose")
              .type(Boolean.class)
              .nargs("?")
              .setConst(true)
              .help("Enable verbose output.");

In the above code listing, an instance of ArgumentParser is instantiated with a static initialization method that expects a String argument representing the script or program name that will be included in usage/help output. The second argument to the ArgumentParsers's newArgumentParse(String, boolean) method specifies that "help" options -h and --help will automatically be supported.

The first argument defined in the above code listing allows for a file path and name to be specified on the command line. The strings "-f" and "--file" are passed to the addArgument(String...) method, meaning that either -f or --file can be used on the command line to specify the file path and name. Three additional methods [dest(String), required(boolean), and help(String)] are called on the instances of Argument created as part of the specification of this first argument. These three methods respectively specify a name by which the argument can be referenced in the code, that the argument must be present on the command line, and the string to be displayed when help is requested for that argument.

The second argument defined in the above code listing passes the strings "-v" and "--verbose" to the addArgument(String...) method to allow this argument to be represented on the command line with either the short or long option name. Like the first argument, this one has the name it will be referenced by in the code set by the dest(String) method and has its string for "help" output specified with the help(String) method. This second argument is not required and so the required(boolean) method is unnecessary here.

The second argument's definition has a few additional methods on Argument called. I used type(Class<T>) to demonstrate the ability to explicitly specify the Java data type expected for the argument. I also needed to specify the combination of the nargs(String) and setConst(Object) methods to specify that the verbosity argument does not need a value provided with the flag. This allows me to specify -v or --verbose with no "true" or "false" after those options expected to be explicitly stated.

The "parsing" stage of command-line processing is supported in argparse4j with a call to the ArgumentParser's parseArgs(String[]) method. The next code listing demonstrates this.

"Parsing" Command Line Arguments with Argparse4j

final Namespace response = argumentParser.parseArgs(arguments);

Parsing requires only a single statement and returns an instance of Namespace.

The "interrogation" stage of command line processing with Argparse4j involves accessing the parsed command-line arguments from the Map that the Namespace instance wraps. The keys of this map are the strings specified with the dest(String) method and the values of the map are the values associated with those argument names. Interrogating these values is demonstrated in the next code listing.

"Interrogating" Command Line Arguments with Argparse4j

final String filePathAndName = response.getString("file");
final Boolean verbositySet = response.getBoolean("verbose");

out.println(
     "Path/name of file is '" + filePathAndName
   + "' and verbosity is "
   + (Boolean.TRUE.equals(verbositySet) ? "SET" : "NOT SET")
   + ".");

In the just listed code, the keys of "file" and "verbose" were used because those same strings were provided with the dest(String) method when defining the expected arguments.

The full source code from which the code snippets above were extracted can be seen on GitHub.

The next screen snapshot demonstrates running the simple Java application without any arguments and the message that is displayed regarding the missing required "file" argument.

The all uppercase "FILE" shown in the above screen snapshot comes from the string that was specified in the dest(String) method when defining the expected argument. In other words, that dest(String) specification set both the string by which the argument mapping is keyed internally and the target string displayed in the help/usage.

The next screen snapshot demonstrates several variations of typical uses of the "file" and "verbose" options.

The final screen snapshot demonstrates that help information that is provided for -h or --help options because the original instance of ArgumentParser was created with the "addHelp" argument set to true.

Here are some additional characteristics of Argparse4j to consider when selecting a framework or library to help with command-line parsing in Java.

  • Argparse4j is open source and licensed with the MIT License.
  • The argparse4j-0.7.0.jar (December 2015) is approximately 89 KB in size and has no additional third-party library dependencies.
  • Argparse4j does not make use of annotations.
  • The online documentation includes a Clojure example.
  • I suspect that Java developers who write their scripts in Python (particularly if they use argparse) would experience advantages when using argparse4j in their Java applications that need to parse command-line arguments.
    • (I find Apache Commons CLI to be intuitive when processing command-line arguments in Java because I much more frequently parse command line arguments in Groovy than in Java and Groovy supplies built-in Apache Commons CLI support)
  • Argparse4j inspired the development of argparse4s for Scala.

Argparse4j is just one of many Java-based command line processing libraries. The characteristic of Argparse4j that most sets it apart from the numerous other options is its argparse heritage. Given that, I believe that the Java developers most likely to select Argparse4j for their Java command line processing needs would be those developers who frequently parse command line arguments in Python-based scripts and tools using argparse or who prefer command parsing semantics of Python and argparse.

Additional References

Monday, July 10, 2017

Java Command-Line Interfaces (Part 7): JCommander

This is the seventh post in my series that briefly introduces various libraries for processing command-line arguments in Java. This post returns to coverage of an annotation-based library that seems to be one of the better known and more popular of the numerous available libraries for processing command line arguments from Java: JCommander.

JCommander's web page states, "Because life is too short to parse command line parameters" and the Overview introduces JCommander as "a very small Java framework that makes it trivial to parse command line parameters." The code examples and associated screen snapshots of the executing code in this post are based on JCommander 1.72 (June 2017). The full code for the demonstrations shown here is available on GitHub.

JCommander uses annotations to implement the "definition" stage of command-line processing. This is demonstrated in the next code listing snippet.

"Definition" Stage with JCommander

/**
 * Demonstrates use of JCommander for Java-based command-line processing.
 */
public class Main
{
   @Parameter(names={"-v","--verbose"},
              description="Enable verbose logging")
   private boolean verbose;

   @Parameter(names={"-f","--file"},
              description="Path and name of file to use",
              required=true)
   private String file;

   @Parameter(names={"-h", "--help"},
              description="Help/Usage",
              help=true)
   private boolean help;

   // . . .

final JCommander commander
   = JCommander.newBuilder()
              .programName("JCommander Demonstration")
             .addObject(this)
             .build();

The just-shown code listing demonstrates use of JCommander's @Parameter annotation to define the command-line options via annotation of class fields. The examples demonstrate specification of names to indicate multiple option flags to be associated with a single option, description to provide a description of each option, required=true to enforce presence of a command-line argument, and help=true to indicate a "help" or "usage" command-line argument (instructs JCommander to not throw exception if required arguments are not also provided).

With the class attributes annotated with @Parameter annotations, an instance of the class with annotated fields can be used to create an instance of the JCommander class. In the code example above, I took advantage of the JCommander.Builder for the greater fluency and other advantages associated with use of builders. In particular, the instance with annotated class fields is added via the addObject(Object) method.

The "parsing" stage of command-line processing with JCommander is accomplished via a single line invocation of the parse(String...) method on the instance of JCommander that was just instantiated. This is demonstrated in the next code listing.

"Parsing" Stage with JCommander

commander.parse(arguments);

The "interrogation" stage of command-line processing with JCommander involves simply accessing the annotated fields of the instance passed to the JCommander class instantiation. This is demonstrated in the next code listing.

"Interrogation" Stage with JCommander

if (help)
{
   commander.usage();
}
else
{
   out.println(
      "The file name provided is '" + file + "' and verbosity is set to " + verbose);
}

The last code listing demonstrates the ability to determine if the boolean attribute with name help was set by the specification of --help or -h. Because it's a simple boolean, it can be used in the conditional and, if true, the help/usage information is presented. In the case when the "help" flag was not set, values associated with the other command line options ("verbose"/-v/--verbose and "file"/-f/--file) are accessed.

The most recent code listing also demonstrates writing the usage information to standard output via an invocation of the method usage() on the instance of the JCommander class. It's worth noting that ParameterException also has a usage() method.

The next series of screen snapshots demonstrate using JCommander with a simple application that includes the above code snippets. The first image shows running the JCommander-based application without any arguments and shows the ParameterException that is displayed in that case because the required --file/-f option was not specified.

The next screen snapshot demonstrates "normal" execution when the expected command line arguments are provided.

The next screen snapshot demonstrates use of the "help" option. Because this was annotated with help=true, the absence of the required "file" command-line argument does not lead to an exception and the automatically generated help/usage information is written to standard output.

JCommander provides a feature that I really like for developing with and learning JCommander. One can specify increased verbosity of the JCommander parsing by invoking the method verbose(int) on JCommandBuilder.

Increasing JCommander's Verbosity

final JCommander commander
   = JCommander.newBuilder()
               .programName("JCommander Demonstration")
               .addObject(this)
               .verbose(1)
               .build();

With the increased verbosity, greater insight into what JCommander is doing related to command-line processing can be discovered and this is demonstrated in the following two screen snapshots.

Here are some additional characteristics of JCommander to consider when selecting a framework or library to help with command-line parsing in Java.

Additional References

Saturday, July 8, 2017

Java Command-Line Interfaces (Part 6): JOpt Simple

The main web page for JOpt Simple calls this Java-based library "a Java library for parsing command line options, such as those you might pass to an invocation of javac," that "attempts to honor the command line option syntaxes of POSIX getopt() and GNU getopt_long()." This is the sixth post of my series of command-line arguments processing in Java and its focus is on JOpt Simple.

Most of the libraries I've reviewed in this series of command-line processing in Java take use annotations in some way. JOpt Simple, like Apache Commons CLI, does not use annotations. JOpt Simple supports "fluent interfaces" instead. This original post's examples (code listings) and output (screen snapshots) are based on compiling and running against JOpt Simple 4.9, but they have worked similarly for me (and without code changes) when compiling them and running them with JOpt Simple 5.0.3.

The next code listing demonstrates the "definition" stage of command-line processing with JOpt Simple and this example is intentionally similar to that used in the previous posts on command-line processing in Java.

Defining Command-line Options in JOpt Simple

final OptionParser optionParser = new OptionParser();
final String[] fileOptions = {"f", "file"};
optionParser.acceptsAll(Arrays.asList(fileOptions), "Path and name of file.").withRequiredArg().required();
final String[] verboseOptions = {"v", "verbose"};
optionParser.acceptsAll(Arrays.asList(verboseOptions), "Verbose logging.");
final String[] helpOptions = {"h", "help"};
optionParser.acceptsAll(Arrays.asList(helpOptions), "Display help/usage information").forHelp();

This code listing demonstrates use of the "fluent API" approach to defining command-line options. An OptionParser is instantiated and then one of its overloaded acceptsAll methods is called for each potential command-line option. The use of acceptsAll allows multiple flag/option names to be associated with a single option. This support for option synonyms allows for use of "-f" and "--file" for the same option.

The code above demonstrates that a command-line option can be specified as required with the .required() method invocation. In this case, a "file" is required. If an argument is expected to be placed on the command line in association with the option/flag, the withRequiredArg() method can be used. The "help" option in the above code listing takes advantage of the forHelp() method to tell JOpt Simple to not throw an exception if a required option is not on the command-line if the option associated with the forHelp() is on the command-line. This works, in my example, to ensure that the operator could run the application with -h or --help and without any other required option and avoid an exception being thrown.

The JOpt Simple Examples of Usage page provides significant details about the many different possibilities available when defining command-line options and uses JUnit-based assertions to demonstrate how these different tactics for defining command-line options configure differently what is parsed. My code listing shown above only shows a minor subset of what's available. Note that the Javadoc comments for the OptionParser class also contain significant details.

The code above can be even more concise if one statically imports the Arrays.asList and passes the potential command-line options' names as strings directly to that asList(String...) method instead of using the approach I used of creating an array of Strings first and then converting them to a list. I used this approach in this introductory post to make it very clear what was happening, but it's likely that the version of the code associated with this post on GitHub will be changed to use the static import approach.

The "parsing" stage of command-line processing with JOpt Simple is, well, simple:

final OptionSet options = optionParser.parse(arguments);

"Parsing" with JOpt Simple entails invocation of the method OptionParser.parse(String ...)

The "interrogation" stage of command-line processing with JOpt Simple is also simple and is demonstrated in the next code listing.

out.println("Will write to file " + options.valueOf("file") + " and verbosity is set to " + options.has("verbose"));

The single line of code demonstrates that interrogation consists of calling convenient methods on the instance of OptionSet returned by the parsing call. In this case, two demonstrated methods called on OptionSet are OptionSet.valueOf(String) and OptionSet.has(String).

JOpt Simple also supports automatic generation of a usage/help statement. The next code listing demonstrates doing this.

optionParser.printHelpOn(out);

The single line of code just shown writes the usage/help information generated by the instance of OptionParser to the output stream provided to it via its printHelpOn(OutputStream) method.

With the most significant code needed for applying JOpt Simple shown, it's time to see how the simple application that uses this code behaves. The following screen snapshots demonstrate the code in action. The first screen snapshot demonstrates the MissingRequiredOptionsException printed when the required "file" command-line option is not provided.

The next screen snapshot demonstrates specifying the "file" and "verbose" options on the command lines.

The automatic usage/help message provided by JOpt Simple is demonstrated in the next screen snapshot.

Here are some additional characteristics of Apache Commons CLI to consider when selecting a framework or library to help with command-line parsing in Java.

  • JOpt Simple is open source and is licensed under the MIT License.
  • As of this writing, the latest versions of JOpt Simple are 5.0.3 and 6.0 Alpha 1; JOpt Simple 4.9 (latest version currently listed in the JOpt Simple change log and version currently shown in Maven dependency example) was used in this post.
  • The jopt-simple-4.9.jar is approximately 65 KB in size and has no compile-time dependencies on any third-party libraries.
  • JOpt Simple has been or is used by several influential libraries and frameworks. These include Spring Framework (optional compile dependency) and JMH (compile dependency).
    • The main page for the JOpt Simple web page quotes Mark Reinhold, "I thought you might be interested to know that we're using your jopt-simple library in the open-source Java Development Kit. Thanks for writing such a nice little library! It's far cleaner than any of the other alternatives out there."
  • JOpt Simple has been available for several years, but appears to still be maintained (latest on Maven Central is December 2016).
  • JOpt Simple does not use annotations and instead relies on fluent API calls.
  • JOpt Simple supports relationships between command-line options such as required dependent options.

It is typically a positive sign of a library's usefulness when other well-received and useful tools and libraries make use of that library. JOpt Simple's selection as the command-line processing library of choice for some such tools and libraries definitely speaks well of JOpt Simple. JOpt Simple provides a useful and powerful alternative to Apache Commons CLI for those who prefer Java command-line processing that does not use annotations. JOpt Simple provides significant more capability than that shown in this post and this capability is best discovered by reading the unit test-based "tour through JOpt Simple's features."

Additional References

Friday, June 30, 2017

Java Command-Line Interfaces (Part 5): JewelCli

After looking at command-line processing in Java with Apache Commons CLI, args4j, jbock, and Commandline in previous posts, I turn attention in this post to using JewelCli to accomplish similar processing of command-line arguments in Java.

Several Java command-line processing libraries use annotations to define the command-line options. Three of the four libraries covered in this series of posts so far use annotations and so does JewelCli. JewelCli is unique among the libraries I've covered so far because its annotations are applied on a Java interface rather than on a Java class or class's constructs. The next code listing demonstrates how to use annotations on a Java interface to implement the "definition" stage of command-line parsing with JewelCli.

JewelCli "Definition" Implemented with Annotated Interface

package examples.dustin.commandline.jewelcli;

import com.lexicalscope.jewel.cli.Option;

/**
 * Interface defining JewelCli-friendly command-line parameters.
 */
public interface MainCommandLine
{
   @Option(shortName="f", description="Name and path of file to be used.")
   String getFile();

   @Option(shortName="v", description="Indicate whether status should be reported verbosely.")
   boolean isVerbose();

   @Option(helpRequest=true, description="Usage details on command-line arguments.")
   boolean getHelp();
}

The simple interface shown above packs a lot related to command-line processing. The options have their single-hyphen short names explicitly specified with shortName annotation type element and implicitly specified via the name of the "get" method (though a longName annotation type element is available for explicitly specifying the long name [double hyphens] version of the switch). The command-line options also have their respective descriptions provided via the Option annotation. The use of helpRequest=true describes what command-line switch should be used to display usage/help information. In this case, because the annotation method is named getHelp(), the --help switch will display usage information. Had I named the method getDustin() and annotated it with @Option(helpRequest=true), the switch would be --dustin to display usage.

JewelCli takes advantage of convention over configuration in cases besides the long name of the switch matching the method names. With the command-line options' corresponding interface method definitions annotated as shown above, the verbosity switch (which returns a boolean) is optional. The file name switch is required because its corresponding getFile() method returns a String. If I wanted to make the file name optional, I could provide a defaultValue to the @Option annotation on the getFile() method such as @Option(defaultValue="").

With the interface (named MainCommandLine in this case) annotated with JewelCli @Option annotations, we can move to the "parsing" stage with JewelCli. This is demonstrated, along with the "interrogation" stage, in the next code listing for Main.

"Parsing" and "Interrogation" Stages with JewelCli

package examples.dustin.commandline.jewelcli;

import static java.lang.System.out;

import com.lexicalscope.jewel.cli.CliFactory;

/**
 * Demonstrates use of JewelCli for parsing command-line
 * parameters in Java.
 */
public class Main
{
   public static void main(final String[] arguments)
   {
      final MainCommandLine main = CliFactory.parseArguments(MainCommandLine.class, arguments);
      out.println("You specified file '" + main.getFile() + "' with verbosity setting of '" + main.isVerbose() + "'.");
   }
}

The Main class just shown has one line that "parses" [the call to CliFactory.parseArguments(Class<T>, String...)] and one line that "interrogates" [the line that accesses the methods defined on the JewelCli-annotated interface shown earlier].

The following three screen snapshots demonstrate the JewelCli-based code examples in action. The first image demonstrates use of --help to see usage (notice that a stack trace is included in the output). The second image shows different combinations of long (-) and short (--) option switches. The third image shows the output message and associated stack trace that are presented when a required command-line argument (--file or -f in this case) is not provided.

The code listings for both classes used in this post to demonstrate application of JewelCli are available on GitHub.

Here are some additional characteristics of JewelCli to consider when selecting a library to help with command-line parsing in Java.

  • JewelCli is open source and licensed under an Apache Software License, Version 2.
  • The current JewelCli (0.8.9) JAR (jewelcli-0.8.9.jar / February 2014) is approximately 542 KB in size.
  • No additional libraries are needed to use JewelCli.
  • As shown in the example above, JewelCli uses annotations on Java interfaces for the "definition" stage. Any attempt to annotate class "get" methods in a similar way results in a message such as "IllegalArgumentException: ... is not an interface" at runtime.
  • JewelCli allows interfaces to inherit from super interfaces and @Options defined in parent interfaces will be supported in the inheriting interfaces.
  • The return data types of the methods annotated in the interface provide type enforcement of the command-line options' values. Enums can even be used as return data types to narrow down the possible command-line option types to a finite set of possibilities.

JewelCli is easy to use and, thanks to its convention over configuration approach, requires very little code to define, parse, and interrogate command-line arguments. I find the recommended approach of annotating an interface for defining the parseable command-line options to be aesthetically pleasing as well.

Additional Resources

Wednesday, June 28, 2017

Java Command-Line Interfaces (Part 4): Commandline

This fourth part of my series on command-line parsing in Java features Commandline, which is described as "a Java library to parse command line arguments" that "is based on a mapping from the command line arguments onto objects, by using annotations."

Like previously covered args4j and jbock, Commandline employs annotations to provide the "definition" of potential command-line options. However, while args4j does this via annotations on class fields and jbock does this via annotations on the constructor and its parameters, Commandline uses annotations on "set" (mutator) methods. In this post, I use a Main class example as in the previous posts on Java-based command-line processing, but in normal situations, I'd typically prefer to have a special class representing command-line arguments.

The following code listing demonstrates use of Commandline annotations on "get" methods to implement the "definition" stage of Commandline's command-line processing.

Commandline "Definition" Stage of Command-line Processing

public class Main
{
   /** Is verbosity enabled? */
   private boolean verbose;

   /** Name/path of applicable file. */
   private String fileName;

   @Option
   @ShortSwitch("v")
   @LongSwitch("verbose")
   @Toggle(true)
   public void setVerbose(final boolean newVerbose)
   {
      verbose = newVerbose;
   }

   @Option
   @ShortSwitch("f")
   @LongSwitch("file")
   @SingleArgument
   @Required
   public void setFileName(final String newFileName)
   {
      fileName = newFileName;
   }

The code listing above shows the use of Commandline annotation @Option along with other annotations that customize the defined option (@ShortSwitch and @LongSwitch for short and long arguments, @Required for mandatory arguments, @SingleArgument to specify one argument associated with switch, and @Toggle to indicate that the presence or absence of the switch is what's significant [no argument associated with that switch]).

The next code listing demonstrates the "parsing" and "interrogation" stages of command-line parsing with Commandline.

"Parsing" and "Interrogating" with Commandline

try
{
   // "Parsing" stage.
   final Main main = CommandLineParser.parse(
      Main.class, arguments, OptionStyle.LONG_OR_COMPACT);

   // "Interrogation" stage.
   out.println("You provided file name of '" + main.fileName
      + "' and verbose is set to '" + main.verbose + "'.");
}
catch (IllegalAccessException | InstantiationException | InvocationTargetException exception)
{
   out.println("ERROR: Unable to parse command-line arguments: " + exception);
}

The last code example demonstrates that parsing is accomplished with the single CommandLineParser.parse(Class<T>, String[], OptionStyle) call and interrogation is as simple as accessing the members of the instance returned by that method. The third argument provided to the parse method is significant because it instructs the parser how to expect the switches to be presented.

The code example just shown uses OptionStyle.LONG_OR_COMPACT, which the documentation describes: "Long switches are prepended by two dashes. Short switches are prepended with a single dash, and may be concatenated into one switch." In contrast, OptionStyle.SIMPLE instructs the parser to expect "All switches have to be standalone" and "all (both long and short) needs to be prepended with a single dash on the command line."

The next screen snapshot demonstrates this simple application in action.

When a required argument is not provided, a message (including stack trace) like that shown in the next screen snapshot is presented.

I don't include an example of using help or usage based on Commandline here because, as the project's GitHub page states, "Generating a help text" is "functionality that is currently not supported." The complete code listing for the class used in this post to demonstrate use of Commandline is available on GitHub.

Here are some additional characteristics of Commandline to consider when selecting a library to help with command-line parsing in Java.

Commandline is another of the plethora of open source command-line processing libraries available to Java developers and, like several of the others, uses annotations to do most of the heavy lifting.

Additional References

Monday, June 26, 2017

Java Command-Line Interfaces (Part 3): jbock

In the first two posts of this series on command-line parsing in Java, I looked at the Apache Commons CLI and args4j libraries. In this third post in the series, I look at jbock, the self-described "curiously simple CLI parser."

My posts on command-line parsing in Java have used examples based on providing a required file name and an optional verbose flag to the Java application. The same approach is used in this post to demonstrate jbock 1.8. The full source code for the example class is available on GitHub, but the code generated by jbock (Main_Parser) is not available as it can be generated.

The approach jbock uses for command-line processing is different than that used by the two previously covered parsing libraries. The previously covered libraries required Java code for parsing command-line arguments to be built against and executed against the libraries' JARs. In other words, the libraries' JARs needed to be on both the compile-time (javac) classpath and on the runtime Java launcher (java) classpath. The jbock approach instead relies on inclusion of the jbock JAR only at compile time. The jbock approach generates Java source code that is completely independent of the jbock library. One could, for example, choose to run jbock to generate these Java source code files once and then version control those generated files and only build and run against the generated files from that point on without needing to build or run against jbock's JAR. The only time the jbock JAR is required is when the generated Java source needs to be regenerated. Because the generated code is generated based on annotations on custom Java classes, it is likely that the jbock code generation would be executed in most cases as part of a normal build rather than version controlling the generated source.

In most situations, I'd use a custom class with a name such as "Arguments" or "CommandLine" when using jbock to parse command-line arguments. However, for this post, I am using a simple Main class to be more similar of an example to the approach used with the other command-line parsing libraries in other posts in this series. Like args4j, jbock uses annotations for the "definition" phase of command-line processing. However, jbock's annotations are on the class's constructor and its arguments rather than args4j's approach of annotating class fields. The jbock constructor-based annotations approach is demonstrated in the next code listing.

jbock "Definition" of Command-Line Options

@CommandLineArguments
public Main(
   @ShortName('v') @LongName("verbose") @Description("Verbosity enabled?")
   final boolean newVerbose,
   @ShortName('f') @LongName("file") @Description("File name and path")
   final Optional<String> newFileName)
{
   verbose = newVerbose;
   file = newFileName.orElse("");
}
// . . .

The "parsing" stage of command-line processing with jbock is demonstrated in the next code listing.

"Parsing" Command-line Options with jbock

final Main_Parser parser = new Main_Parser();
final Main_Parser.Binder binder = parser.parse(arguments);
final Main main = binder.bind();

The Main_Parser class shown in the above code listing is generated by jbock based on the annotations shown in the first code listing. The jbock library processes the annotations of the Main class to determine how to build the Main_Parser class. The generated class's name is based on the name of the class with jbock annotations and concatenated with _Parser. For example, had my class with jbock annotated constructor and constructor arguments been named "Arguments", the generated class would be named "Arguments_Parser".

After the instance of the generated Main_Parser class has had parse invoked on the command-line arguments, that instance's bind() method is invoked to return an instance of the original annotated Main class. The "interrogation" process at this point consists solely of accessing the attributes of that Main instance via its public "get" methods. This is demonstrated in the next code listing.

"Interrogation" Stage of Command-line Processing with jbock

out.println("The file '" + main.getFile() + "' was provided and verbosity is set to '"
   + main.isVerbose() + "'.");

The screen snapshot that follows demonstrates the code in action using jbock to parse the command-line options.

If help or usage information is desired, this can be retrieved from the generated *_Parser (Main_Parser in this case) class as well. Specifically, the generated *_Parser class includes a nested Option enum representing the various options. One can iterate over those option's enum values to retrieve metadata about each option. In the code listing below, the describe(int) method is invoked on each option's enum value (the passed-in integer is the number of spaces to indent).

Obtaining Usage Details with jbock

final Main_Parser parser = new Main_Parser();
if (arguments.length < 1)
{
   for (final Main_Parser.Option option : Main_Parser.Option.values())
   {
      out.println(option.describe(3));
   }
   System.exit(-1);
}

The screen snapshot shown next demonstrates this code in action to print out the options and their descriptions.

The source code discussed in this post is available on GitHub.

Here are some additional characteristics of jbock to consider when selecting a framework or library to help with command-line parsing in Java.

  • jbock is available as open source.
    • UPDATE: jbock creator h908714124 has pointed out in the feedback that jbock is "just a concept project" that is "intentionally minimalistic, so you can actually grok all the parsing rules."
    • UPDATE: h908714124 also invites users of jbock to "open a github issue or make a pull request" if an issue is identified.
  • The current version of jbock (1.8) requires Java SE 8.
  • jbock has no third-party or external dependencies.
  • The jbock 1.8 JAR (jbock-1.8.jar) is approximately 131 KB in size, but this is not as significant as for similar libraries because this JAR is not required at runtime (generated code is independent of the JAR).
  • I did not demonstrate jbock's enforcement of the presence of required command-line parameters because it intentionally does not support that feature. The README states, "Deliberately simple: No converters, default values or required checking. With java 8, it's easy to add this stuff by hand."

The most obvious characteristic of jbock that distinguishes it from most other Java-based command-line parsing libraries is the generation of parsing code entirely at compile time that leaves no runtime dependencies on the jbock library. This would be an obvious advantage in situations where there is concern about the number of classes loaded or the size of the expressed classpath. The README lists multiple items that "set [jbock] apart." These include "no reflection, purely static analysis" and "convenient, flexible property binding via constructor."

Additional References