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