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

@Override
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 https://java.ziesemer.com/.
    • 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

Saturday, October 14, 2017

Java Command-Line Interfaces (Part 23): Rop

The Rop library is described on its main page as "a lightweight command line option parser written in Java." The "Introduction" to Rop also states, "Rop is designed to be minimal meanwhile convenient, and to cover most usual command line parsing use cases." This post is the twenty-third in this series on parsing command line arguments in Java and focuses on Rop.

Like the twenty-two posts in this series before this one, this post uses examples implementing two command line options, one for file path and name and one for verbosity level. The full code listing the example is available on GitHub.

The "definition" stage is accomplished in Rop via annotations @Command and @Option (both of which are nested within class com.github.ryenus.rop.OptionParser). This is shown in the next code listing.

"Definition" Stage with Rop

/**
 * Demonstrates use of Rop for processing command line
 * parameters in Java.
 */
@Command(name="RopDemo", descriptions="Demonstrates ROP for command line processing.")
public class Main
{
   @Option(opt={"-f", "--file"}, description="Path and name of file.")
   private String file;

   @Option(opt={"-v", "--verbose"}, description="Indicates whether verbosity is enabled or not.")
   private boolean verbose;

The "parsing" stage is accomplished in Rop by instantiating an instance of OptionParser and pass to it the definition of the class whose fields were annotated in the "definition" stage. This is shown in the next code listing.

"Parsing" Stage with Rop

final OptionParser parser = new OptionParser(Main.class);
parser.parse(arguments);

The OptionParser.parse(Class) method implicitly invokes (via reflection) a method with name "run" on the instance provided to the parser when it was constructed. I have implemented this "run" method as shown in the next code listing.

"Interrogation" Stage with Rop (including "run" method)

/**
 * Method called implicitly by Rop parser.
 *
 * @param parser Instance of {@code OptionParser} whose
 *    "parse" method led to my implicit invocation.
 */
private void run(final OptionParser parser)
{
   out.println("File path/name is " + file + " and verbosity is " + verbose);
}

The above code listing's "run" method demonstrates "interrogation" that is accomplished by accessing the @Option-annotated fields that were populated by the OptionParser.parse(String[]) call.

The three screen snapshots that follow demonstrate these "definition", "parsing", and "interrogation" stages accomplished with Rop. The first image indicates the error message that is shown when the required "file" option is not specified. The second image depicts normal behavior of the example that processes combinations of the "file" and "verbose" options' short and long names. The third image depicts Rop's built-in "help" support that is shown when the --help option is specified.

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

  • Rop is open source with an MIT License.
  • Rop, as advertised, is lightweight; the rop-1.1.1.jar is approximately 18 KB in size and requires no third-party dependencies.
  • The classes in the rop-1.1.1.jar have "major version: 51", meaning that Java SE 7 is required if using these compiled classes.

Rop is a lightweight Java-based library for processing command line options that is easy to learn and use.

Additional References

Thursday, October 12, 2017

Java Command-Line Interfaces (Part 22): argparser

John Lloyd's argparser is the library covered in this twenty-second post of the series on Java-based command line argument parsing. The main page for the library provides links to Javadoc-based API documentation, a JAR file, a ZIP file, and a TAR file in addition to a single source code example. The example used in this post is similar to the examples used in the first twenty-one posts in this series and processes file path/name and verbosity options. The full code listing is available on GitHub.

The "definition" stage is accomplished in argparser with instances of "Holder" classes representing the expected options that are passed to the addOption(String,Object) method of an ArgParser instance. This is demonstrated in the next code listing.

"Definition" Stage with argparser

final StringHolder file = new StringHolder();
final BooleanHolder verbose = new BooleanHolder();

final ArgParser parser = new ArgParser("java examples.dustin.commandline.argparser.Main");
parser.addOption ("-f,--file %s #Path and name of file", file);
parser.addOption ("-v,--verbose %v #Verbosity enabled?", verbose);

Many of the libraries covered in this series on parsing command line arguments from Java have option characteristics explicitly spelled out with individual parameters, individual methods, or individual annotation elements. As shown in the code listing, argparser instead has the option's attributes spelled out in a "specification" string that argparser parses.

The "parsing" stage is accomplished in argparser by passing the String[] with command-line arguments to the matchAllArgs(String[]) method of the ArgParser class. This single statement is shown in the next code listing.

"Parsing" Stage with argparser

parser.matchAllArgs(arguments);

The "interrogation" stage is accomplished in argparser by accessing the public field called "value" in the respective "Holder" classes. This is shown in the next code listing.

"Interrogation" Stage with argparser

out.println("File path/name is: " + file.value);
out.println("Verbosity is: " + verbose.value);

The argparser library also provides support for a "help"/"usage" message. This is demonstrated in the next code listing in which usage is written if the "file" option is not specified (if its "value" is null).

"Usage" with argparser

if (file.value == null)
{
   out.println("ERROR: File path/name was not specified! Use -f or --file to specify file path/name.\n"
      + parser.getHelpMessage());
}

The screen snapshots shown next demonstrate the examples covered in this post. The first image shows the "usage" provided by argparser when the required "file" option is not specified. The second image shows use of the long and short option names.

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

  • Arparser is open source. It's not clear to me if it is licensed under any specific license, but there is a COPYRIGHT file included with the JAR that states, "Copyright John E. Lloyd, 2004. All rights reserved. Permission to use, copy, modify and redistribute is granted, provided that this copyright notice is retained and the author is given credit whenever appropriate." There is also a standard disclaimer about the software being distributed "as-is."
  • The argparser.jar is approximately 129 KB in size, but includes .java source code files, .class compiled files, and Javadoc HTML files.
  • The Javadoc for the argparser.ArgParser class is excellent and an example of what I'd love to see routinely in Javadoc for "main" classes of Java-based libraries. This is a good example of how a small open source project can document the project/library once because the class's Javadoc is also used and link to from the project's main page. That class-level Javadoc even includes the SimpleExample source code (which is also in the distributed JAR file) for an example of how to use the class and library.
  • Because argparser is compiled with "major version: 46", it should run with a version of Java as old as JDK 1.2!

The argparser library is small and simple to use. It will probably appeal most to those wanting a small library to accomplish basic command line processing and will especially appeal to anyone who still might happen to be running their Java-based command-line processing code in older versions of JDK. A couple of things that make this library different than many of the others covered in this series are its excellent Javadoc-based API documentation and its string specification approach for option characteristics.

Additional References

Monday, October 9, 2017

Java Command-Line Interfaces (Part 21): Airline 2

The focus of this twenty-first post in this series on parsing command-line arguments in Java is on the Airline 2 library. The GitHub project page for Airline 2 describes the library, "Airline is a Java library providing an annotation-based framework for parsing command line interfaces." The page goes onto state that Airline "supports both simple single commands through to complex git style interfaces with groups." The page also defines Airline 2's relationship with the original Airline library: "This is a substantially rewritten fork of the original airline library." It is specifically Airline 2.3.0 that is featured in this post.

The examples in this post will be similar to those demonstrated in earlier posts in this series on alternative libraries for parsing command line arguments from Java. As such, the options supported in these examples will be specification of a file's path and name and specification of whether or not verbosity should be enabled. The full code listing for the examples shown here is available on GitHub.

The "definition" stage of parsing command-line arguments from Java with Airline 2 is easily accomplished using @Option annotations as shown in the next code listing.

"Definition" Stage with Airline 2

@Option(title="file", name={"-f", "--file"}, description="Path and name of file.")
private String file;

@Option(title="verbose", name={"-v", "--verbose"}, description="Enable or disable verbosity.")
private boolean verbose;

The code for these instances of @Option annotations is fairly self-explanatory. The "name" element of the @Option annotation expects one or more Strings and thus allows multiple flags to be specified for the same option. In this case, I used the same single-hyphen/single-character "short" form and double hyphen/word "long" forms for the options.

The "parsing" stage can be accomplished with Airline 2 using the SingleCommand class and its static singleCommand(Class<C>) method to acquire an instance of SingleCommand and then invoking the parse(String[]) method on that instance. These two statements are demonstrated in the next code listing.

"Parsing" Stage with Airline 2

final SingleCommand<Main> parser = SingleCommand.singleCommand(Main.class);
final Main main = parser.parse(arguments);

The "interrogation" stage in Airline 2 is accomplished by simply accessing the @Option-annotated fields of the instance provided by the SingleCommand.parse(String[]) method. This is demonstrated in the next code listing.

"Interrogation" Stage with Airline 2

if (main.file != null)
{
   out.println("File path/name is '" + main.file + "'.");
   out.println("Verbosity is " + main.verbose);
}
else
{
   out.println("ERROR: File path/name must be provided with -f or --file.");
}

The next two screen snapshots show the examples in action. The first screen snapshot shows the output when no arguments are provided and the second image shows "normal" use of the long and short versions of the two options for specifying file path/name and verbosity.

Airline comes with support for generating usage and help information. Unfortunately, I was not able to get it to work for me because I ran into a compilation error that stated, "class file for com.github.rvesse.airline.io.printers.UsagePrinter not found." I don't see that class in the airline-2.3.0.jar I downloaded.

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

  • Airline 2 is open source and licensed under the Apache License, Version 2.0.
  • Airline 2 is one of the "weightier" libraries covered in this series with the airline-2.3.0.jar being approximately 316 KB in size and having runtime dependencies on Apache Commons Collections, Apache Commons Lang, and javax.inject/javax.inject.
  • Although Airline has been around for a while, Airline 2 is a more recently updated fork of that project.
  • The documentation for basic use of Airline 2 is straightforward and useful, but documentation for many of the features not shown in this post is still under construction with numerous "TODO" statements.

Airline 2 is easy to use for the "single command" style of arguments processing implemented in my examples in these posts. I did not see any method for expressing whether an option is required, but simply checking for null for a required option before proceeding is an easy approach for this. Given its size and dependencies, Airline 2 is probably best suited for those looking to use many of its powerful features not demonstrated in this post. For the simple examples demonstrated in this post and in the other posts in this series, there are lighter libraries with fewer dependencies that work very similarly to Airline 2 in terms of expressing "definition", "parsing", and "interrogation" stages.

Additional References

Wednesday, October 4, 2017

Java Command-Line Interfaces (Part 20): JSAP

JSAP (Java Simple Argument Parser) 2.1 is the focus of this twentieth post in this series on processing command line arguments from Java. The JSAP page describes the library's reason for existence: "I found several parsers on the Internet, all of which handled switches, but none of which had the versatility I wanted in terms of return types and configuration files."

JSAP offers quite a bit of flexibility at the normal cost of some complexity. Fortunately, JSAP provides a class called SimpleJSAP that makes it easier to accomplish simple tasks with JSAP. The JSAP documentation articulates it this way, "If you want to minimize the amount of code handling the command line, JSAP offers a SimpleJSAP that does most of the work for you." The next code listing demonstrates using SimpleJSAP in a single (albeit verbose) statement to define the expected command line options.

"Definition" Stage with JSAP

final SimpleJSAP jsap = new SimpleJSAP(
   "Main Application",
   "Demonstrate JSAP",
   new Parameter[]
      {new FlaggedOption("file", STRING_PARSER, NO_DEFAULT, REQUIRED, 'f', "file", "File path/name."),
       new Switch("verbose", 'v', "verbose", "Requests verbose output." )});

For the above code listing, I used static imports to reduce the verbosity of this "definition" code. These can be seen in the full code listing available on GitHub. The code above defines the two options being used in all of the posts in their series on libraries used to parse command line arguments in Java: file path/name and verbosity. The single characters 'f' and 'v' are the short option names and the long option names follow them in their respective calls (file and verbose). Note that the "definition" of command line arguments can be configured via XML as well, though that is not demonstrated here.

The "parsing" stage is accomplished in JSAP with another single statement in which an invocation of the parse(String[]) method on the instance of SimpleJSAP returns an instance of JSAPResult.

"Parsing" Stage with JSAP

final JSAPResult parsedResult = jsap.parse(arguments);

JSAP's "interrogation" stage is accomplished with calls on the instance of JSAPResult returned by the parse method as demonstrated in the next code listing.

"Interrogation" Stage with JSAP

out.println("File path/name is '" + parsedResult.getString("file") + "'.");
out.println("Verbosity level is " + parsedResult.getBoolean("verbose"));

JSAP will generate automatic usage and help statements. The next code listing demonstrates use of the SimpleJSAP.messagePrinted() method to determine if some time of parsing error occurred and then using the SimpleJSAP.getHelp() message to access the automatically generated "help" message.

"Help" with JSAP

if (jsap.messagePrinted())
{
   out.println(jsap.getHelp());
   System.exit( -1 );
}

The next two screen snapshots demonstrate execution of the code examples shown in this post using JSAP. The first image depicts the usage statement printed when the required -f/--file flag is not provided. The second image depicts normal behavior of the example code based on JSAP.

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

JSAP seems to be one of the more popular of the older Java-based command-line parsing libraries. It's relatively easy to use for basic functionality like that demonstrated in this post, but also offers additional flexibility and customizability for more complex needs.

Additional Resources

Tuesday, October 3, 2017

Java Command-Line Interfaces (Part 19): jClap

The focus of this nineteenth post in this series on parsing command line arguments from Java code is jClap (Java Command Line Argument Parser), which should not be confused with the library called JCLAP that was the focus of my previous post in this series. The previous post covered JCLAP 1.4 by Giles Winstanley (snaq.net) whereas this post covers jClap 2.0 by Jan So (extreme_logic).

The "definition" stage is implemented jClap by instantiating an instance of com.extremelogic.common.jclap.Argument and invoking one of the overloaded methods with names addArgument or addBooleanArgument. This is demonstrated in the next code listing (full code in available on GitHub).

"Definition" Stage with jClap

final Argument argument = new Argument(arguments);
argument.addArgument("file", "Path/name of file", true, 1);
argument.addBooleanArgument("verbose", "Enables verbosity", false);

The previous code listing demonstrates providing of long argument names, argument descriptions, whether the argument is required or not, and the number of values expected for the argument. As far as I can tell, there's no way to add a short name (single hyphen and single character) for arguments.

The "parsing" stage is achieved via jClap through invocation of the processArguments() method on the instance of Argument defined in the "definition" stage. This is a single-line call, but does throw the checked exception ArgumentException. This single-line parsing is shown in the next code listing.

"Parsing" Stage with jClap

argument.processArguments();

The "interrogration" stage is achieved with jClap via invocation of the getArgument methods on the instance of Argument that was defined in the "definition" stage. This is demonstrated in the next code listing.

"Interrogation" Stage with jClap

out.println("File path/name is '" + argument.getArgument("file") + "'.");
out.println("Verbosity is set to " + argument.getArgument("verbose"));

jClap also makes it easy to have usage written to standard output by invoking the method displayOptions on the Argument instance that was used throughout this example. This is demonstrated in the next code listing which shows catching and "handling" the checked exception ArgumentException.

"Usage" in jClap

catch (final ArgumentException argumentException)
{
   out.println(
        "ERROR: Exception encountered while processing command-line arguments - "
      + argumentException);
   argument.displayOptions();
}

Screen snapshots demonstrate the code covered in this post applying jClap to command line processing. The first image depicts the handling of the checked exception ArgumentException when the required --file argument has not been specified and also depicts the usage statement provided by jClap. The second image depicts normal command line processing of the arguments.

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

  • jClap is open source with an Apache License Version 2.0.
  • The commons-jClap-2.0.0.jar JAR is approximately 15 KB in size and has no third-party library dependencies.
  • It appears to me that jClap only supports "long" argument names with double hyphens.
  • The jClap JAR contains class files compiled with Java SE 6 (Major Version 50) and so should work with Java applications running on a version as old as Java SE 6.
  • All arguments are retrieved from the instance of Argument as Strings (there is no typing of arguments).
  • The jClap JAR also includes a "sample" application (SampleArguments.class) that IDE decompilers (such as IntelliJ IDEA's built-in decompiler and Eclipse's Enhanced Class Decompiler) can decompile to see the type of source code one can write to use jClap.

jClap is a small and easy-to-use library for processing command line arguments from Java that can be used with Java applications running on versions of Java as old as Java SE 6. The library supports long argument names only and returns arguments' values as String type in all cases.

Additional Resources

Monday, October 2, 2017

Java Command-Line Interfaces (Part 18): JCLAP

Giles Winstanley's JCLAP (Java Command-Line Argument Parser) is the eighteenth library covered in this series of posts on Java-based command line processing libraries. This post's examples are based on JCLAP 1.4, which requires Java 8. The main JCLAP page states, "JCLAP helps Java developers to create simple-to-use command-line interfaces for their applications."

The "definition" stage is accomplished with JCLAP via invocation of "addXXXXXOption" methods on the CLAParser object. This post's example, as was the case for examples in the earlier posts in this series, defines two command line options, one for file path and name and one for enabling verbosity. The next code listing demonstrates how to use JCLAP to define these two command line options (full code listing is available on GitHub).

"Definition" Stage with JCLAP

final CLAParser parser = new CLAParser();
final Option<String> fileNameOption
   = parser.addStringOption("f", "file", "Path/name of the file.", 1, 1);
final Option<Boolean> verbosityOption
   = parser.addBooleanOption("v", "verbose", "Verbosity enabled?");

The code listing just shown demonstrates that JCLAP supports long and short argument names, the ability to provide a description, and the ability to designate the minimum and maximum number of occurrences of each argument.

The "parsing" stage is implemented via JCLAP with a single invocation of the method CLAParser.parse(String[]), though that method does throw the checked exception OptionException.

"Parsing" Stage with JCLAP

parser.parse(arguments);

The "interrogation" stage is implemented in JCLAP in different ways, but the approach I use here is to use one of the overloaded CLAParser.getOptionValue() methods.

"Interrogation" Stage with JCLAP

out.println("File path/name is " + parser.getOptionValue(fileNameOption));
out.println("Verbosity is " + (parser.getOptionValue(verbosityOption) != null));

JCLAP also supports automatic usage statement creation. The next code listing demonstrates invoking one of the overloaded CLAParser.printUsage() methods in the block associated with catching the checked OptionException.

Automatic Usage Statement with JCLAP

catch (OptionException optionException)
{
   out.println("Exception: " + optionException);
   parser.printUsage(out, true);
}

The two screen snapshots that follow depict the code examples in action. The first screen snapshot shows the JCLAP-generated usage statement when no arguments are provided. The second image shows the "happy path" applying the long and short flag names for the two arguments.

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

  • JCLAP is open source with a "BSD-style licence" described on the project page.
  • The jclap-1.4.jar JAR file is approximately 46 KB in size and has no third-party library dependencies.
  • Different versions of JCLAP are designed for different versions of Java.
  • JCLAP's author has offered potential support and bug fixes as requested by e-mail.
  • JCLAP provides some support for internationalization and localization.

JCLAP (Java Command-Line Argument Parser) is a small library with commercial-friendly license that has been updated in recent years to use Java 8 features. JCLAP's author has written on the project's main page that "JCLAP is by no means unique, and many similar utilities are available both for free and commercially." The author further explains that "So many similar solutions now exist that it seems redundant to have yet another, but having already created JCLAP it seems beneficial to make it publicly available."

Additional References

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

Saturday, August 26, 2017

Java Command-Line Interfaces (Part 13): JArgs

JArgs 1.0 has the distinction of being the subject of the 13th post of my series on parsing command line arguments in Java. JArgs is an open source (BSD license) library that has been primarily supported by different contributors including Steve Purcell and Ewan Mellor. It turns out that this can lead to some confusion when first using JArgs because package names and other details change depending on which version of JArgs you apply.

The JArgs project page describes JArgs as "a convenient, compact, pre-packaged and comprehensively documented suite of command line option parsers for the use of Java programmers." The page asserts that JArgs might be selected over other Java-based command line processing libraries because JArgs is "easy to use, thoroughly tested, well documented and liberally licensed (BSD licence so no GNU messiness)." The page also states, "The package is small and without frills, but is functional, and contains code that has been in production use for quite some time."

JArgs is indeed small. The jargs-1.0.zip file is under 200 KB in size and the extracted core jargs.jar is only about 12 KB. There are no third-party library dependencies. The following screen snapshot demonstrates the contents of jargs.jar downloaded from SourceForge (the jargs-1.0.jar available on the Maven Repository is similar).

The documentation for JArgs consists primarily of its Javadoc-generated API documentation and code examples such as OptionTest and CustomOptionTest.

When using JArgs, the main class one uses is CmdLineParser (jargs.gnu.CmdLineParser or com.sanityinc.jargs.CmdLineParser depending on where you get your distribution of JArgs and which version you get). If using the JArgs JAR available via SourceForge download or via the Maven Repository, the primary class you'll be using is jargs.gnu.CmdLineParser. On the other hand, if you build JArgs from source available on GitHub (purcell/jargs), the main class will be com.sanityinc.jargs.CmdLineParser. In either case, there is just the one CmdLineParser outer class and it uses nested classes for additional support. In this post, I'm demonstrating examples based on the SourceForge/Maven JARs with jargs.gnu.CmdLineParser. The full source code of my examples will be posted on GitHub and that version will likely be edited to take advantage of more explicit imports for greater code conciseness and readability.

JArgs is small and so surprisingly is simple. It doesn't provide a lot of fancy features, but it does do basic command line argument processing with a simple programmatic approach that doesn't make use of annotations or reflection.

To implement the "definition" stage of command-line argument parsing with JArgs, one instantiates an instance of the CmdLineParser class and invokes the addOption(CmdLineParser.Option) method on that instance for each anticipated command line option. Each option is represented by an instance of a class that extends the CmdLineParser.Option class. In the examples in this series, I have been using a String-based file path/name option and a boolean-based verbosity option. So, when using JArgs for these examples, I can use the class CmdLineParser.Option.StringOption for file path and name and the class CmdLineParser.Option.BooleanOption for the verbosity option. The next code listing demonstrates implementation of the "definition" stage with JArgs.

"Definition" Stage with JArgs

public static void main(final String[] arguments)
{
   final CmdLineParser cmdLineParser = new CmdLineParser();
   final CmdLineParser.Option fileOption = new CmdLineParser.Option.StringOption('f', "file");
   cmdLineParser.addOption(fileOption);
   final CmdLineParser.Option verbosityOption = new CmdLineParser.Option.BooleanOption('v', "verbose");
   cmdLineParser.addOption(verbosityOption);

"Parsing" with JArgs requires just one statement, but you do need to catch the two checked exceptions thrown by the CmdLineParser.parse(String[]) method or explicitly state that these are thrown from your code that invokes with method. This is shown in the next code listing.

"Parsing" Stage with JArgs

try
{
   cmdLineParser.parse(arguments);
}
catch (CmdLineParser.IllegalOptionValueException | CmdLineParser.UnknownOptionException exception)
{
   out.println("Unable to parse command line options - " + exception);
   System.exit(-1);
}

When the code just shown executes successfully (without throwing either of the two checked exceptions), the instance of CmdLineParser upon which the parse(String[]) method was invoked now contains the values parsed for the expected command-line options and so we're ready to "interrogate" that instance.

JArgs "interrogation" stage of command line options processing uses methods on the CmdLineParser.Option-extending classes discussed earlier to retrieve the values parsed for each of those options. There are overloaded versions of the CmdLineParser.getOptionValue() methods for performing this interrogation. The method accepting only the instance of Option whose value is desired [getOptionValue(CmdLineParser.Option)] returns null if the option wasn't found or parsed. The method accepting the instance of Option whose value is desired and a second "default" object [getOptionValue(CmdLineParser.Option, Object)] returns the provided default object if that option was not found or parsed. In the code listing below, I use the second form in both cases and thus ensure I don't have to deal with null.

"Interrogation" Stage with JArgs

final String filePathName = cmdLineParser.getOptionValue(fileOption, "null").toString();
if (filePathName.equals("null"))
{
   out.println("ERROR: File path/name must be provided.");
   System.exit(-2);
}
out.println(
     "File path/name is " + filePathName
   + " and verbosity is " + cmdLineParser.getOptionValue(verbosityOption, false)
   + ".");

With these basic code examples in place, running the simple Java application that uses JArgs to command-line processing is demonstrated in the following screen snapshot.

The CmdLineParser class does not come with any built-in help/usage support. However, the jargs-1.0.zip available on SourceForge includes the source code for AutoHelpParser, a class which extends CmdLineParser and illustrates how help/usage could be implemented.

Because it's dated and due to its simplicity, JArgs can probably be used with older versions of Java than some of the other Java-basd command-line parsing libraries discussed in this series. When I run javap on CmdLineParser in the Maven-provided jargs-1.0.jar and the SourceForge-provided jargs.jar, to determine the version of Java it was compiled with, I see that it's major version 45! As I wrote in my post "Programmatically Determining Java Class's JDK Compilation Version", a major version of 45 indicates that the code was compiled with JDK 1.1!

Maven-provided jargs-1.0.jar Version Information from javap

Classfile jar:file:/C:/lib/jargs-1.0/lib/jargs-1.0.jar!/jargs/gnu/CmdLineParser.class
  Last modified Apr 9, 2005; size 6032 bytes
  MD5 checksum b2d61c0ce786f8a661cccf1e61de2a19
  Compiled from "CmdLineParser.java"
public class jargs.gnu.CmdLineParser
  minor version: 3
  major version: 45

SourceForge-provided jargs.jar Version Information from javap

Classfile jar:file:/C:/lib/jargs-1.0/lib/jargs.jar!/jargs/gnu/CmdLineParser.class
  Last modified Apr 9, 2005; size 6032 bytes
  MD5 checksum b2d61c0ce786f8a661cccf1e61de2a19
  Compiled from "CmdLineParser.java"
public class jargs.gnu.CmdLineParser
  minor version: 3
  major version: 45

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

  • JArgs is open source and is licensed with the BSD license.
  • There seems to be some confusion about versions and primary contributors to JArgs with Maven and SourceForge having one version and purcell/jargs on GitHub having another version.
  • JArgs is small and simple: the jargs.jar (or jargs-1.0.jar on Maven) is only about 12 KB in size and there are sno third-party library dependencies.
  • JArgs uses programmatic APIs for defining, parsing, and interrogating options rather than using annotations or reflection.
  • JArgs is a bit dated with many of its main pages having "latest updates" with years such as 2005. However, the GitHub page referenced in this post several times, and which has the different package name for its main class, shows its last updates being 2012.
  • I believe that JArgs could be used with the vast majority of Java applications today as it appears to me to be able to work with Java versions as far back as Java SE 1.1.

The most compelling reasons one might have to use JArgs instead of some of the other more commonly used and/or more recently updated Java-based command-line processing are its simplicity and small size. I sometimes face the decision of what level of command-line options I want to support JArgs provides a library that might be desirable when I want just a bit more than directly parsing the passed-in String[] to the main function, but don't want the power and complexity of some of the other Java-based command line processing libraries. My biggest concerns about using JArgs are probably that it hasn't been updated in a while and the potential confusion that could result for others using my work and having to deal with two different manifestations of JArgs with difference package name for its main class (using Maven for the dependency could help a lot here). JArgs is small and simple and might find its niche for those only desiring the most basic command line processing.

Additional References