Monday, October 16, 2017

Java Command-Line Interfaces (Part 24): MarkUtils-CLI

The first post in this series on parsing command line arguments in Java featured the Apache Commons CLI library. This is one of the oldest and likely one of the most commonly used of the Java-based command-line parsing libraries covered in this series. Apache Commons CLI does show its age, especially when contrasted with some of the more modern Java-based command-line processing libraries. Mark A. Ziesemer's "CLI library wrapper on Apache Commons CLI," called MarkUtils-CLI, was designed to "modernize" Apache Commons CLI and is the subject of this blog post.

In the blog post "MarkUtils-CLI: Annotations (and more) for Apache Commons CLI," Ziesemer writes:

I feel that the Apache Commons CLI project is selling themselves short. I've found it to be a very comprehensive, well-designed library for effectively parsing the command-line. The only shortcoming I've observed is that the project was developed before Java 5 - and annotations - were available. As such, the library doesn't offer support for any features that annotations have to offer.

Introducing the latest addition to MarkUtils: MarkUtils-CLI is a library that provides an effective bridge between Apache Commons CLI and Java annotations - without replacing the mature Commons CLI library.

This post uses examples similar to those used in earlier posts in this series ("file" and "verbose" command line options) to illustrate how MarkUtils-CLI wraps Apache Commons CLI and allows for definition of options via annotations and provides typed options. In this post, MarkUtils-CLI's CliRunner is used for its convenience. The full source code listing for these examples is available on GitHub.

The "definition" stage with MarkUtils-CLI is where @Parameter annotations are applied as shown in the next code listing.

"Definition" Stage with MarkUtils-CLI

@Parameter(name="f", longName="file", description="Path/name of file", required=true)
public String file;

@Parameter(name="v", longName="verbose", description="Verbosity enabled or not", argCount=0)
public boolean verbose;

This code listing shows how the "short" option name (single hyphen/single character") and "long" option name (double hyphens/word) can be specified as distinct elements of the @Parameter annotation. A "description" element can be used in the "help" created by MarkUtils-CLI and the "required" annotation element allows one to specify a required option. Specifying argCount as zero for "verbose" also indicates to the parser that no arguments are expected for the "verbose" option.

The "parsing" stage can be accomplished in MarkUtils-CLI via the CliRunner and an instance of an Apache Commons CLI CommandLineParser. This is demonstrated in the next code listing where an instance of Apache Commons CLI's DefaultParser is passed to the constructor of the CliRunner along with an instance of the class whose fields are annotated with the @Parameter annotation.

"Parsing" Stage with MarkUtils-CLI

final DefaultParser cmdLineParser = new DefaultParser();
final CliRunner<Main> cliRunner = new CliRunner(cmdLineParser, Main.class);

When using MarkUtils-CLI's CliRunner approach, the "interrogation" stage is accomplished in the call() method of the Callable that is passed to the CliRunner's "run" method. The implementation of the "call()" method is shown in the next code listing and the code that passes the owning Callable to the CliRunner's "run" method is available in the full source code listing on GitHub.

"Interrogation" Stage with MarkUtils-CLI

public Integer call() throws Exception
   out.println("File path/name is '" + file + "' and verbosity is " + verbose);
   return file != null ? 0 : -1;

The two screen snapshots that follow demonstrate the examples shown so far. The first image shows the help information generated when the required "file" option is not provided. The second image depicts the behavior of the sample code for various combinations of short name and long name options for "file" and "verbose."

There are characteristics of MarkUtils-CLI to consider when selecting a framework or library to help with command-line parsing in Java.

  • MarkUtils-CLI is open source and licensed under GNU General Public License version 3.
  • MarkUtils-CLI is available as a separate JAR, but is conceptually part of the greater MarkUtils available at
    • It seems appropriate that this approach mirrors that of Apache Commons CLI in which the CLI JAR is separate from the other JARs that are available for each library falling under the Apache Commons line.
    • This approach allows more flexibility in terms of what needs to be made available on the runtime classpath as opposed to an approach where all utilities are in a single JAR (such as with CmdLn and the Ostermiller Utilities).
  • The com.ziesemer.utils.cli-2017.05.28.jar JAR is relatively small (approximately 26 KB), but has runtime dependencies on external libraries Apache Commons CLI (expected because MarkUtils-CLI wraps this library) and SLF4J (because SLF4J is a widely used library, this dependency may not be much of an issue for many).
  • MarkUtils-CLI requires Java SE 6.
  • The author of MarkUtils-CLI notified me of the existence of this library and appears to be actively involved in supporting it, something that cannot be said for all the libraries covered in this series. He has stated that he is "committed to responding to and fixing anything that would come across" the MarkUtils-CLI GitHub Issues Tracker. He also pointed out that there are 95 executing unit tests verifying MarkUtils-CLI functionality.

MarkUtils-CLI is a small wrapper for Apache Commons CLI that modernizes the Apache Commons CLI experience through use of annotations and handling of command line options' types. MarkUtils-CLI will most likely appeal to those who are already using Apache Commons CLI and want to enjoy the benefits of easier options definition with annotations and more type safe option parsing. Advantages of this library include current support and thorough unit testing of the library. Issues that may deter some from using this library are its GPL license and its external dependency on SLF4J (assuming the Apache Commons CLI dependency is not an issue as this is advertised as a wrapper for Apache Commons CLI).

Additional References

No comments: