Friday, September 29, 2017

Java Command-Line Interfaces (Part 17): jw-options

The JavaWorld article Processing command line arguments in Java: Case closed by Dr. Matthias Laux introduces a simple Java-based library for processing command-line arguments that I'll refer to in this post as jw-options. The referenced article provides background information on why certain design decisions were made in construction of the Options class. The "Conclusion" of the article describes the advantage of using the accompanying class and library: "This article describes a Java class that allows for the convenient processing of command line options for Java programs. The structure is flexible enough to handle even complex situations, while at the same time offering an API that allows for the definition of acceptable command line syntax with limited coding effort."

The "library" introduced by this JavaWorld article consists of three Java classes: Options, OptionData, and OptionSet. This is demonstrated in the following screen snapshot that displays the contents of options.jar.

The "definition" stage with "jw-options" is achieved with its Options and OptionSet classes. This is demonstrated in the next code listing (full code listing is available on GitHub and the example here is similar to those used in earlier posts in this series).

"Definition" Stage with jw-options

final Options options = new Options(arguments, Multiplicity.ZERO_OR_ONE);
final OptionSet defaultOptions = options.getSet();
defaultOptions.addOption("f", false, Separator.BLANK, Multiplicity.ONCE);
defaultOptions.addOption("v", Multiplicity.ZERO_OR_ONE);

The code listing just shown demonstrates using a couple of OptionSet's overloaded addOption methods. For setting up the option for file path and name (-f), a four-argument version is called with the single-letter of the flag ("f"), the separator between the flag and its argument (a space), and the number of times the flag should be expected (exactly one occurrence). The second argument for verbosity ("-v") is set up by calling the two-argument version of addOption that specifies the flag's character ("v") and its number of expected occurrences (zero occurrences or single occurrence).

The "parsing" stage is achieved in "jw-options" by invoking Options's check method. This method can also be used, as its name suggests, to check the accuracy of the arguments. This is demonstrated in the next code listing.

"Parsing" Stage with jw-options

if (!options.check(false, false))
{
   out.println("ERROR: " + options.getCheckErrors());
   System.exit(-1);
}

In the "parsing" example just shown, the Options class's method getCheckErrors() was used to access the errors in the parsed parameters that led to the Options.check method returning false.

The "interrogation" stage with "jw-options" is demonstrated in the next code listing.

"Interrogation" Stage with jw-options

out.println("File path/name is " + defaultOptions.getOption("f").getResultValue(0));
out.println("Verbosity is set to " + defaultOptions.isSet("v"));

The "interrogation" example demonstrates using OptionSet's getOption method to access the option representing the "-f" option and then calls its getResultValue(0) method to access the first (and only in this case) value associated with that "-f" flag. The second line in that example inquires simply whether the "-v" flag has been specified or not (and does not worry about or expect a value to be associated with that flag) via use of the OptionSet's method isSet.

A screen snapshot is shown next to demonstrate the code shown so far that uses "jw-options." The image shows the messages reported when expected command line arguments are not provided and ends with two examples using the command line flags as intended.

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

  • The "jw-options" "library" is open source in the sense that it's source code is thoroughly introduced and discussed in the JavaWorld article "Processing command line arguments in Java: Case closed and the source code is included in the JAR available for download as the jw-0816-command.zip ZIP file." However, the license for this "library" is not obvious.
  • The "jw-options" library is small: the options.jar file is approximately 13 KB in size.
  • There is no third party library dependency for "jw-options."
  • As far as I can tell, there's no way to specify "long" flag names with double hyphens with "jw-options."
  • The javap command run on classes in the "jw-options" jar show "major version: 49", meaning that it's compiled against J2SE 5 and should work with applications running on Java as old as J2SE 5 (I noticed use of StringBuffer in the code where StringBuilder would have worked just as well).

The "jw-options" "library" discussed in this post is most likely to interest those who need to use a command line processing library with an older version of Java or who are interested in it in an academic sense. Because this "library" is described in detail in the associated JavaWorld article and because it's open source, one can peruse the code and review the article to see how it accomplishes the command line parsing and why it uses that approach. Given that the license for "jw-options" is not obvious and given that this is a relatively "old" library that doesn't seem to receive updates, it is likely that most Java developers would prefer some of the alternate libraries covered in this series over "jw-options" in many cases.

Additional References

Saturday, September 23, 2017

Java Command-Line Interfaces (Part 16): JArgp

The Java-based command line argument processing library covered in this post was the featured library of an IBM developerWorks article Java programming dynamics, Part 3, Applied reflection (this 2003 article was "archived" in 2016, but is still available for PDF download). The library, called JArgp (Java Command Line Argument Processing Library), is defined on its main web page as "a library for processing command line arguments in Java." This page adds, "Unlike most other libraries of this type, JArgp uses reflection to store actual values directly to fields in the target application object." JArgp 1.0 is featured in this post.

JArgp is a minimalistic library as shown by the small number of classes in the JArgp JAR.

The "definition" stage is accomplished in JArgp via specification of an array of ParameterDef instances. Custom classes can be written to extend the ParameterDef class, but I'll be able to use two provided extensions of this class (StringDef and BoolDef) to implement the file path/name and verbosity arguments implemented in earlier posts in this series. This is exemplified in the next code listing (full code will be made available on GitHub).

"Definition" Stage with JArgp

private static final ParameterDef[] PARAMETERS_DEFINITIONS =
{
   new StringDef('f', "file", "File path and name"),
   new BoolDef('v', "verbose", "Verbosity level")
};

The initial argument to the constructors of the ParameterDef-extending classes StringDef and BoolDef is the single character that will be the command-line flag. In this case, the defined command-line argument flags will be "-f" for file path/name and "-v" for verbosity. The second argument of each constructor is the name of the class's field that any values associated with the command line flags will be written to. The third argument to each constructor is a description of that command line argument flag. As far as I can tell, there's no way to specify "long" argument names (no ability to specify --file or --verbose in this case).

The "parsing" stage is accomplished in JArgp with invocation of the static ArgumentProcessor method processArgs(String[], ParameterDef[], Object). This is exemplified in the next code listing.

"Parsing" in JArgp

final Main instance = new Main();
// The integer returned by the next invocation is actually the
// zero-based index of next argument to be processed
final int numberArgumentsProcessed
   = ArgumentProcessor.processArgs(
arguments, PARAMETERS_DEFINITIONS, instance);

The "interrogation" stage with JArgp is implemented by accessing the fields in the instance that have names matching those provided in the parameter definitions. This is shown in the next code listing.

"Interrogation" Stage in JArgp

out.println(
     "File path/name is " + instance.file
   + " and verbosity is " + instance.verbose);

Use of the code shown so far is demonstrated in the next screen snapshot.

If I wanted to apply the descriptions I provided to the command line flags when defining them, I could have used the instance method approach for parsing rather than the static function approach showed earlier. This is demonstrated in the next code listing.

final Main instance = new Main();
final ArgumentProcessor argumentProcessor
   = new ArgumentProcessor(PARAMETERS_DEFINITIONS);
argumentProcessor.processArgs(arguments, instance);
argumentProcessor.listParameters(50, out);

The last line in the previous code listing demonstrates how the ArgumentProcessor.listParameters(int, PrintStream) method can be used to write the flags and their descriptions to output. This output is demonstrated in the next screen snapshot.

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

JArgp is a minimalistic library for processing command line arguments in Java. It doesn't support "long" argument names by default and doesn't support as many features as some of the other libraries covered in this series, but it is small and easy to use. I primarily included it in this series because of its background tied to the IBM DeveloperWorks article.

Additional Resources

Thursday, September 21, 2017

JDK 9 Released Today

The big news in Java today is, of course, the release of JDK 9 in General Availability. Mark Reinhold starts his message JDK 9: General Availability with the statement, "I'm pleased -- nay, thrilled! -- to announce that JDK 9 is now Generally Available."

The Reinhold post adds that in addition to Jigsaw, there are "many other excellent additions and improvements." He lists them with links that are reproduced here:

It will be interesting to see what people learn and share from using JDK 9 over the next several months. We've already seen numerous resources based on early releases of JDK 9, but I'd expect usage and consequential lessons learned to pick up with JDK 9 in General Availability. Recent posts that provide examples of this include Java 9, Jigsaw, JPMS, and Modules: A Personal Exploration and JDK 9: XXtra Command Line Options.

Additional Resources

Friday, September 8, 2017

Java Command-Line Interfaces (Part 15): Jargo

Jargo is defined on its main GitHub page as "a tool to ease the handling of program arguments/options." That page provides a Rationale for another command line processing library when so many others already exist and the top of that list is, "Because type-safety, immutability and readability matters."

Jargo's options "definition" stage uses generic typed instances of the Argument class. These instances of Argument are created via static methods on the Arguments class to establish the type and then using builder-style methods to describe the option. This is demonstrated in the next screen snapshot which depicts definition of options for file path/name and verbosity (full code listing is available on GitHub).

"Definition" Stage with Jargo

final Argument<String> filePathAndName
   = stringArgument().description("Path and name of file.")
                     .names("--file", "-f")
                     .required()
                     .build();
// Use optionArgument() instead of booleanArgument() to avoid need
// to specify true or false as arguments to --verbose/-v option
final Argument<Boolean> verbose
   = optionArgument("--verbose", "-v")
                    .description("Enables verbosity.")
                    .names("--verbose", "-v")
                    .defaultValue(false)
                    .build();

The stringArgument() and optionArgument() methods shown above are called on the statically imported (not shown) Arguments class. The optionArgument() method needed to be used for the verbosity flag to avoid being required to explicitly state true or false after the verbosity flag.

The "parsing" stage is implemented with the class CommandLineParser and its fluent API methods as shown in the next code listing.

final ParsedArguments parsedArguments
   = CommandLineParser.withArguments(filePathAndName, verbose)
                      .parse(arguments);

The instance of ParsedArguments provided by the CommandLineParser can be used for the "interrogation" stage. This is accomplished by invoking the "get" method on the ParsedArguments instance and passing it the appropriate Argument instance. The next code listing demonstrates this.

"Interrogation" Stage with Jargo

out.println("File path/name is '" + parsedArguments.get(filePathAndName)
   + "' and verbosity is set to '" + parsedArguments.get(verbose) + "'.");

The following screen snapshots depict use of Jargo. The first screen snapshot demonstrates the exception stack trace that occurs when a required option is not specified and the second screen snapshot demonstrates the long and short option names being used.

The stack trace shown in the first screen snapshot is not the nicest way to notify the user that a required option was not specified. Jargo allows a nicer message to be returned by catching the ArgumentException and calling its getMessageAndUsage() method. The code for this can be seen on GitHub and the results are shown in the next screen snapshot.

The screen snapshot demonstrates that the information provided in the instantiation of the Arguments is displayed. Jargo also allows an exception to be explicitly thrown to provide this information when a "help" argument is specified. This makes use of the static method helpArgument() on the Arguments class and an example of its usage is included in the GitHub code listing.

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

  • Jargo is open source and is licensed under the Apache License, Version 2.0.
  • Jargo's jargo-0.4.1.jar is approximately 177 KB in size, but it has a runtime dependency on the much larger Guava library.
    • The Guava dependency is an intentional decision as described in Jargo's Rationale: "Because I love Guava and wanted an argument parsing library well integrated with it (more to come in this department)."
    • This is obviously not an issue for the many applications that use Guava, but could be an issue for those wanting a command line processing Java-based library for a simple application that did not otherwise use Guava.
  • Jargo uses strongly typed API invocations to programmatically configure expected command line options rather than using annotations and/or reflection.
  • In a field with so many Java-based command line processing libraries available, Jargo is most likely to be a significant contender for a developer who desires all of the attributes of a command line processing library that Jargo's Rationale lists in explanation of why another library in this crowded space was developed.

Jargo is an easy to use library for processing command line options in Java and makes use of generic-typed classes and type-specific static methods to enforce type safety of command line options. Jargo requires Guava to run and so is best suited for applications already using Guava. A developer is likely to seriously consider Jargo over other alternate Java-based command line processing libraries if the items in the Jargo Rationale are all important to that developer.

Additional References

Wednesday, September 6, 2017

Java Command-Line Interfaces (Part 14): google-options

The GitHub page for google-options states that google-options is a "command line argument parsing library from the folks at Google (java)." The page goes on to say, "This is the command-line arguments parser from the Bazel Project. The com.google.devtools.common.options package has been split out into a separate jar for general utility." This blog post demonstrates applying google-options to processing command line options from Java code.

The example used in this post to demonstrate google-options is similar to the examples used in the earlier thirteen posts in this series on processing command line options in Java. This example supports two options: a required file path/name option expecting a String argument with that path and name and a verbosity option with no argument (its existence enables verbosity). Only the most relevant portions of the code will be shown in this post, but the full code is available on GitHub.

The "definition" stage of Java-based command-line processing is accomplished in google-options via a custom class that extends google-options's class com.google.devtools.common.options.OptionsBase. The custom class should provide public fields that correspond to the expected command line options and each of these public fields should be annotated with the @Option annotation. The @Option annotation requires two elements (name and defaultValue) and allows for optional elements such as help and abbrev. An example of this "definition" stage is provided in the next code listing for the custom Options class.

"Definition" Stage with google-options: Custom Options Class

/**
 * Represents command-line options to be processed via
 * google-options library. Fields must be annotated with
 * @Option and must be public.
 */
public class Options extends OptionsBase
{
   @Option(name="file",
           abbrev='f',
           help="Path and name of file",
           category="Startup",
           defaultValue="")
   public String filePathAndName;

   @Option(name="verbose",
           abbrev='v',
           help="Enable verbose output",
           category="Startup",
           defaultValue="false")
   public boolean verbose;
}

The required "name" element of the @Option annotation specifies the "long" option name while the optional "abbrev" element specifies the "short" (single character) option name. The optional "help" element of the @Option annotation allows one to provide a "help" string for the option and the required "defaultValue" element specifies the default value for the option to be used when the option is not explicitly specified.

The "parsing" stage is accomplished in google-options by instantiating an instance of OptionsParser associated with the custom class with Option-annotated public fields and then invoking a "parse" method on that instance of OptionsParser. The next code listing demonstrates this with invocation of the OptionsParser.parseAndExitUponError(String[]) method.

"Parsing" Stage with google-options

final OptionsParser optionsParser = OptionsParser.newOptionsParser(Options.class);
optionsParser.parseAndExitUponError(arguments);

The "interrogation" stage with google-options is as simple as accessing the Option-annotated public fields on the custom class as demonstrated in the next code listing.

"Interrogation" Stage with google-options

out.println(
     "Path/file name is '" + options.filePathAndName
   + "' and verbosity is '" + options.verbose + "'.");

The next code listing demonstrates how the OptionsParser method describeOptions can be used for displaying help details.

Using google-options's "Help"

private static void printUsage(OptionsParser parser)
{
   out.println("Usage: java Main <Options>");
   out.println(parser.describeOptions(Collections.emptyMap(),
   OptionsParser.HelpVerbosity.LONG));
}

The following screen snapshots demonstrate the above code listings. The first image depicts the "help" information provided when no arguments are provided and the second image depicts the two main command line options expressed in various long and short forms. One interesting observation that can be made from that second image is that google-options automatically supports a --noversion option for the boolean option explicitly specifying no verbosity.

The screen snapshots also demonstrate that google-options has a dependency on Guava.

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

  • google-options is an open source library licensed with the Apache License 2.0.
  • The google-options-1.0.0.jar is approximately 72 KB in size.
  • Applications using google-options also need to include Guava on the runtime classpath because google-options has a dependency on Guava. For applications using Guava anyway, this is not a big deal. However, for small applications not already using Guava, this may be more of a dependency than the application authors would like to have for a simple command-line based application.

Several of the Java-based command line processing libraries covered in this series use annotations to define the expected options and this is the approach used by google-options. Basic processing of command line options with google-options is a relatively straightforward process, but the cost of a new Guava dependency may be too high of a cost for simple applications that don't already depend on Guava.

Additional References