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

No comments: