Thursday, October 26, 2017

Java Command-Line Interfaces (Part 29): Do-It-Yourself

This series on parsing command line arguments from Java has briefly introduced 28 open source libraries that can be used to process command-line arguments from Java code. Even with these 28 libraries covered, the series has not covered all available open source libraries for parsing command line options from Java. For example, this series has not covered docopt, dolphin getopt, DPML CLI, the "other" JArgP, java-getopt, ritopt, cli-args, clio, TE-CODE Command, and likely many other libraries I'm not aware of. This post looks at considerations one might make when attempting to decide whether to roll one's own command line argument parsing code in Java versus using one of the plethora of command line parsing libraries that is already available.

At first glance, it would be easy to say that someone developer their own command-line parsing code in Java might be suffering from Not Invented Here Syndrome. However, I still occasionally write my own simple command line processing code and will outline the situations in which I do this.

Many of the libraries covered in this series are small. However, for cases where the command line parsing is very simple, even these smaller libraries may be heavier than what is needed for the job at hand. The examples I show in this post are the type that might fit this category. The likelihood of a developer developing custom command line processing code likely increases as the complexity of required command line parsing increases and as the difficultly of introducing new libraries to one's deployment environment decreases. Process can also influence the decision as some developers may choose to implement their own command line processing code rather than wait for requisite approvals to use the identified library.

The easiest situation to choose to not use a command-line parsing library for Java is obviously those situations in which command line arguments are not necessary. In fact, it is likely that far more Java developers never or rarely use command-line options given that so many use web servers, application servers, or other containers (such as Spring) to run that they don't think about command-line parsing for their application. Even some simple command-line-based applications may be able to assume values or read values from an assumed location and don't need arguments passed to them.

If I only have a single argument to read from the command line, I'll write that simple code myself. The Java Tutorials feature a section on Command-Line Arguments that introduces basic handling of command line arguments in Java. The zero to many strings on the command line following the Java executable application's name are provided to the Java application via the String[] or String... arguments to the classic "public static void main" function. The simple code listing below indicates how a single expected command-line argument might be processed.

Parsing Single Required Argument

/**
 * Demonstrate processing a single provided argument.
 *
 * @param arguments Command-line arguments; expecting a
 *    String-based name.
 */
public static void main(final String[] arguments)
{
   if (arguments.length < 1)
   {
      out.println("\nNo name provided; please provide a name.\n");
      out.println("\tUSAGE: SingleArgMain <name>");
   }
   else
   {
      out.println("Hello " + arguments[0] + "!");
   }
}

The above code was easy to write because there was one command line option, it did not have an argument to go with the option, and it was required. With all of these assumptions in place, it is relatively easy to write command line parsing code.

If the application requires two arguments, it is still pretty straightforward to handle this directly in Java without a third-party library. This is demonstrated in the next code listing that simulates an application that accepts the name/path of an XML file to be validated and the name/path of the XSD against which that XML is to be validated.

Parsing Two Required Arguments

/**
 * Demonstrate processing two required provided arguments.
 *
 * @param arguments Command-line arguments; expecting a String-based
 *    path and file name of an XML file to be validated and a
 *    String-based path and file name of the XSD file against which
 *    the XML file will be validated.
 */
public static void main(final String...arguments)
{
   if (arguments.length < 2)
   {
      out.println("\nXML file path/name and XSD file path/name not provided.\n");
      out.println("\tUSAGE: TwoArgsMain <xmlFilePathAndName> <xsdFilePathAndName>");
   }
   else
   {
      out.println("The provided XML file is '" + arguments[0]
         + "' and the provided XSD file is '" + arguments[1] + "'.");
   }
}

In the posts in this series, I've used examples that expect a required option specifying file path/name and an optional option expressing enabled verbosity. In all of those examples, the file path/name option was a flag name (-f and/or --file) followed by a an "argument" or "value" for that option. For those examples, the verbosity option did not have an argument or value associated with it and the existence of -v or --verbose implied enabled verbosity. This is particularly easy to accomplish directory in Java without a library if I'm willing to change the approach slightly and assume the the first command line option is the file path/name and to assume that the verbosity flag, if provided, occurs after the file path/name. The other assumption that makes this easy is to assume that because the file path/name is first, I don't need to actually use a flag such as -file or -f. With all of these assumptions in place, the code example is shown next.

Series Example: Parsing One Required Option and One Optional Option

/**
 * Demonstrate parsing of command-line options for required file
 * path/name and for optional verbosity.
 *
 * @param arguments Expected command-line arguments; first String
 *    should be file path/name and, if applicable, second String
 *    should be the verbosity flag (-v or --verbose).
 */
public static void main(final String[] arguments)
{
   if (arguments.length < 1)
   {
      out.println("\nNo file path/name provided; please provide a file path/name.\n");
      out.println("\tUSAGE: SeriesExample <filePathAndName> [-v|--verbose]");
   }
   else
   {
      final String file = arguments[0];
      final String verboseString = arguments.length > 1 ? arguments[1] : "";
      final boolean verbose = verboseString.equals("-v") || verboseString.equals("--verbose");
      out.println("File path/name is '" + file + "' and verbosity is " + verbose);
   }
}

I've had relatively easy command-line parsing options so far because of these characteristics of these examples:

  • Order of command line arguments was assumed and unchangeable.
  • Never had more than one optional command line argument and the optional argument was expected last.
  • Never needed a command line argument that consisted of flag and value associated with that flag.
  • No option had a dependency on any other option.

The just-mentioned characteristics made for easier parsing of command line options from Java because the number of permutations and combinations to be prepared for were significantly reduced by requiring the ordering of the options, by not allowing for flags with associated values that must be handled together (each string in the provided String[] is independent of all other strings in that array), and by only allowing one optional argument at most (and requiring it to be last).

As the command-line arguments situation gets more complicated, my desire to use a third-party library increases. If I want to have multiple optional arguments or want to have options that consist of flags with associated values, I'm more likely to make the jump to the third-party libraries for parsing command-line arguments in Java. Using most of the third-party libraries covered in this series removes the need for me to worry about option ordering and option name/flag associations.

One situation in which it might be desirable to roll one's own command-line parsing code in Java is when those parsing needs are highly specific to a particular situation that is not handled well by the existing libraries or when none of the existing libraries adequately meet one's needs. However, with 30+ libraries available, I doubt this would occur very frequently for most people.

When developing one's own command-line parsing code in Java, other options besides writing it from scratch include forking and extending one of the open source libraries or building one's code on a framework such as that introduced in the article "Parsing Command Line Arguments with Java: Using an effective Java framework to write command line tools" (pages 20 and 22 of this Java Developer's Journal).

For small Java-based tools, the simple command-line parsing approaches shown in this post are often sufficient, especially if I'm the only one likely to use the tool. However, as the potential user base increases for the Java application, the requirements outlined in this post can become onerous and the use of third-party libraries covered in this series of posts can be helpful in creating a more user-friendly command-line argument experience. For the simplest of Java-based tools and applications, I may be able to get away with my own homemade command-line parsing code. However, for most Java applications of significance, a third-party library will make more sense because it offers significantly greater flexibility and ease of use for the end users.

Additional References

Wednesday, October 25, 2017

Java Command-Line Interfaces (Part 28): getopt4j

The page for getopt4j describes this as "a library to parse command line arguments according to the GNU style." The page then introduces getopt4j: "The 'getopt4j' library is designed to parse the command line options in the same manner as the C getopt() function in glibc (the GNU C runtime library). It attempts to do this in a simpler, more Java-centric manner than the original product." This post describes use of getopt4j to parse command line options in the same manner as was done for the libraries covered in the earlier 27 posts in this series.

The "definition" stage is accomplished in getopt4j via instances of CLOptionDescriptor as demonstrated in the next code listing (full source code is available on GitHub).

"Definition" Stage with getopt4j

final CLOptionDescriptor fileDescriptor
   = new CLOptionDescriptor("file",
      CLOptionDescriptor.ARGUMENT_REQUIRED,
      'f',
      "Path and name of file.");
final CLOptionDescriptor verboseDescriptor
   = new CLOptionDescriptor("verbose",
      CLOptionDescriptor.ARGUMENT_DISALLOWED,
      'v',
      "Is verbosity enabled?");
final CLOptionDescriptor[] optionsDefinitions
   = new CLOptionDescriptor[]{fileDescriptor, verboseDescriptor};

As shown in the above code, the instances of CLOptionDescriptor are placed in an array to be presented to the getopt4j parser.

The "parsing" stage is achieved in getopt4j via instantiation of the CLArgsParser class. The constructor of that class accepts the command line arguments in the String[] array and the array of CLOptionDescriptor instances representing the options' definitions. This is shown in the next code listing.

"Parsing" Stage with getopt4j

final CLArgsParser parser = new CLArgsParser(arguments, optionsDefinitions);

The "interrogation" stage in getopt4j is accomplished by retrieving a List<CLOption> via invocation of the method getArguments() on the CLArgsParser instance. Each instance of CLOption can be queried by its getId() method to acquire the parsed parameter by its "short" name ('f' or 'v' in this example). Once the appropriate instance of CLOption has been found via its getId() method, that same instance of CLOption will provide the value associated on the command line with that option via a call to the CLOption's method getArgument() method. This "interrogation" process is demonstrated in the next code listing.

"Interrogation" Stage with getopt4j

String filePathAndName = null;
boolean verbose = false;
final List<CLOption> options = parser.getArguments();
for (final CLOption option : options)
{
   switch(option.getId())
   {
      case 'f' :
         filePathAndName = option.getArgument();
         break;
      case 'v' :
         verbose = true;
         break;
   }
}

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

The getopt4j library makes it easy to request usage/help information by passing the array of CLOptionDescriptor instances to the static method CLUtil.describeOptions(CLOptionDescriptor[]). This is demonstrated in the next code listing, a couple of lines of code called when it is detected that the file path/name has not been provided.

"Usage" Statement with getopt4j

if (filePathAndName == null)
{
   out.println("ERROR: The file path/name option is required but was not provided.\n\n"
      + CLUtil.describeOptions(optionsDefinitions));
}

The first of the next two screen snapshots depicts the automatically generated "usage" statement that the code is able to invoke when the required "file option is not specified. The second image depicts various combinations of the "file" and "verbose" long and short option names being used.

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

The getopt4j library provides GNU C getopt()-like functionality and APIs with Java style.

Additional References

Tuesday, October 24, 2017

Java Command-Line Interfaces (Part 27): cli-parser

CLI Parser, originally hosted on and now archived on Google Code, is now available on GitHub. The archive Google Code project page describes CLI Parser as a "very simple to use, very small dependency" that uses annotations to "make very succinct main methods that don't need to know how to parse command line arguments with either fields, properties, or method based injection." The current GitHub project page describes CLI Parser as "a tiny ..., super easy to use library for parsing various kinds of command line arguments or property lists."

CLI Parser expects the "definition" stage to be implemented via the @Argument annotation. This is demonstrated in the next code listing, which provides a simple example defining "file" and "verbose" options as has been done in previous posts in this series. The complete code listing is available on GitHub.

"Definition" Stage with CLI Parser

@Argument(alias="f", description="Path/name of the file", required=true)
private String file;

@Argument(alias="v", description="Verbosity enabled?")
private boolean verbose;

The code shown above defines two options. Each option can be specified with a name matching the field name (file or verbose) or with the specified alias (f or v). With CLI Parser, either case (full field name or alias) is expressed on the command-line with a single hyphen. As shown in the code example, an option can be specified as "required" and description text can be provided to be used in help/usage statements.

The "parsing" stage is accomplished in CLI Parser via static functions on its Args class. In this case, I'm using the Args.parseOrExit(Class, String[]) function as shown in the next code listing.

"Parsing" Stage with CLI Parser

final List<String> unparsed = Args.parseOrExit(instance, arguments);

The "interrogation" stage is accomplished by accessing the fields annotated with @Argument as demonstrated in the next code listing.

"Interrogation" Stage with CLI Parser

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

The "definition" code defined the "file" option as "required." If this option is not specified on the command line, CLI Parser automatically prints out a usage statement using the "description" values provided in the respective @Argument annotations. This is shown in the next screen snapshot, which is followed by another screen snapshot indicating combinations of the -file/-f and -verbose/-v options.

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

  • CLI Parser is open source and available under the Apache License, Version 2.
  • CLI Parser is a small, lightweight library with the cli-parser-1.1.2.jar being approximately 15 KB and having no third-party dependencies.

CLI Parser is, as advertised, a "tiny" and "super easy to use library for parsing various kinds of command line arguments." It's liberal open source Apache license makes it easy for most organizations to acquire and use it.

Additional References

Monday, October 23, 2017

Java Command-Line Interfaces (Part 26): CmdOption

I became aware of the twenty-sixth featured Java-based library in this series on parsing command line arguments because of a Tweet. CmdOption is described on its main GitHub page as "a simple annotation-driven command line parser toolkit for Java 5+ applications that is configured through annotations." The project's subtitle is, "Command line parsing has never been easier."

The annotation @CmdOption is used to annotate fields (or methods) that will contain the parsed command-line arguments. In other words, it is with the @CmdOption annotation that the "definition" stage is accomplished with CmdOption. This is shown in the next code listing.

"Definition" Stage with CmdOption

@CmdOption(names={"--file","-f"}, description="File Path/Name", minCount=1, args={"filePathAndName"})
private String file;

@CmdOption(names={"--verbose","-v"}, description="Is verbosity enabled?", maxCount=0)
private boolean verbose;

As with other posts in this series, the examples used in this post are of options specifying file path and name and a verbosity level. The full source code listing for the example code listings in this post is available on GitHub. As the above code listing shows, the "long" (with double hyphen) and "short" (with single hyphen) option names can be specified with the @CmdOption annotation's names element. The minCount element is used to specify that a particular option must have an argument passed to it and the args element lists the string reference to the argument of an option that will be rendered in the help/usage display. The maxCount element is set to 0 for the verbosity option because no arguments should be provided for that option (presence of -v or --verbose is enough).

The "parsing" stage is accomplished in CmdOption by passing an instance of the class with @CmdOption-annotated fields (or methods) to the constructor of the CmdOption's CmdlineParser class and then passing the String[] representing the command-line arguments to the parse(String[]) method of that instantiated CmdlineParser class.

"Parsing" Stage with CmdOption

final Main instance = new Main();
final CmdlineParser parser = new CmdlineParser(instance);
parser.parse(arguments);

The "interrogation" stage in CmdOption consists simply of accessing the @CmdOption-annotated fields (or methods) on the instance of their containing class that was passed to the CmdlineParser constructor.

"Interrogation" Stage in CmdOption

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

CmdOption provides mechanisms to make generation of "help" or "usage" statements easier. If the @CmdOption annotation includes the element isHelp=true, CmdOption won't validate the command-line arguments when the option associated with isHelp=true is specified on the command line. This prevents error messages about missing required options or arguments from being displayed and then the method CmdlineParser.usage() can be invoked to have CmdOption print out usage/help information. A portion of code demonstrating this is shown next.

"Help" with CmdOption

@CmdOption(names={"--help","-h"}, description = "Display this help message", isHelp=true)
private boolean help;

// ...

if (instance.help)
{
   parser.usage(out);
}

The following three screen snapshots show the above code in action and using CmdOption. The first image depicts two error messages, one when no options are specified (-f/--file is required) and one when the "file" option is specified without an argument. The second image depicts the combinations of short and long option names. The third image shows the usage that is printed when the -h or --help option is specified.

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

  • CmdOption is open source and released under the Apache License, Version 2.0.
  • The de.tototec.cmdoption-0.5.0.jar is approximately 82 KB in size and requires no third-party dependencies.
  • CmdOption 0.5.0 is compiled with "major version: 49", meaning that it's compatible with J2SE 5 applications. Although there are multiple libraries covered in this series that have similar annotations to CmdOption's, this ability to work with an older version of Java may be a differentiator in some cases.
  • CmdOption is still being supported; the version covered in this post (0.5.0) was updated earlier this month (9 October 2017).

CmdOption is an easy-to-use library for parsing command-line options in Java. It comes with a liberal open source license and has received recent updates.

Additional References

Thursday, October 19, 2017

Java Command-Line Interfaces (Part 25): JCommando

JCommando is described on the JCommando site as "a Java argument parser for command-line parameters." JCommando reads XML configuration to generate a Java class that handles parsing from a Java application. The only Java-based library previously covered in this series of posts on Java command-line parsing libraries that provided XML configuration is JSAP, but it's a secondary form of configuration with that library and I did not cover XML configuration in my post on JSAP.

Because JCommando uses XML to specify command line options to be parsed, the "definition" stage with JCommando is accomplished via XML specification. As with the previous posts in this series, the examples in this post are based on command line options for file path and name and verbosity and their definition in JCommando-compliant XML is shown in the next code listing (options.xml).

JCommando via XML Portion of "Definition" Stage: options.xml

<jcommando>
   <option id="file" long="file" short="f" type="String">
      <description>Path and name of file</description>
   </option>
   <option id="verbose" long="verbose" short="v">
      <description>Verbosity enabled</description>
   </option>
   <commandless id="execute" allow-optionless="true">
      <or>
         <option-ref id="file" />
      </or>
   </commandless>
</jcommando>

JCommando uses the XML file an input and, based on that XML, generates a Java source code file that parses the options specified in the XML. There are two ways to instruct JCommando to parse this XML and use the details to generate Java source code. One way is to use the executable jcomgen executable provided with the JCommando distribution (in its bin directory). The second approach for generating a Java class from the XML is the approach shown here: using Apache Ant and a JCommando-provided Ant task. This is demonstrated in the next XML/Ant listing.

Ant Target for Generating Source from XML with JCommando

  <target name="generateSourceForJCommando"
          description="Generate command line parsing source code that uses JCommando">
    <taskdef name="jcommando" classname="org.jcommando.ant.JCommando">
      <classpath>
        <pathelement location="C:\lib\jcommando-1.2\lib\jcommando.jar"/>
      </classpath>
    </taskdef>

    <jcommando inputfile="jcommando/options.xml"
               classname="MainParser"
               destdir="src"
               packagename="examples.dustin.commandline.jcommando"/>
  </target>

The above Ant target shows how JCommando allows the input XML file (options.xml) to be specified as the "inputfile" and that the generated Java source code file will be placed in the src directory in a subdirectory structure matching the designated package "examples.dustin.commandline.jcommando". The execution of the Ant target and source code generation is shown in the next screen snapshot.

The result of this Ant target is the generated Java source class MainParser.java whose listing is shown next.

Generated Java Source Class MainParser.java

/*
 * THIS IS A GENERATED FILE.  DO NOT EDIT.
 *
 * JCommando (http://jcommando.sourceforge.net)
 */

package examples.dustin.commandline.jcommando;

import org.jcommando.Command;
import org.jcommando.JCommandParser;
import org.jcommando.Option;
import org.jcommando.Grouping;
import org.jcommando.And;
import org.jcommando.Or;
import org.jcommando.Xor;
import org.jcommando.Not;

/**
 * JCommando generated parser class.
 */
public abstract class MainParser extends JCommandParser
{
   /**
     * JCommando generated constructor.
     */
   public MainParser()
   {
      Option file = new Option();
      file.setId("file");
      file.setShortMnemonic("f");
      file.setLongMnemonic("file");
      file.setDescription("Path and name of file");
      addOption(file);

      Option verbose = new Option();
      verbose.setId("verbose");
      verbose.setShortMnemonic("v");
      verbose.setLongMnemonic("verbose");
      verbose.setDescription("Verbosity enabled");
      addOption(verbose);

      Command execute = new Command();
      execute.setName("commandless");
      execute.setId("execute");
      execute.addOption(file);
      execute.setGrouping( createExecuteGrouping() );
      addCommand(execute);

   }

   /**
     * Called by parser to set the 'file' property.
     *
     * @param file the value to set.
     */
   public abstract void setFile(String file);

   /**
     * Called by parser to set the 'verbose' property.
     *
     */
   public abstract void setVerbose();

   /**
     * Called by parser to perform the 'execute' command.
     *
     */
   public abstract void doExecute();

   /**
    * Generate the grouping for the 'execute' command.
    */
   private Grouping createExecuteGrouping()
   {
      Or or1 = new Or();
      or1.addOption(getOptionById("file"));
      return or1;
   }
}

With the Java source code generated, we now have our options definitions. A custom class is written to extend the generated MainParser and to access its parent for parsing. This is demonstrated in the next code listing of the custom written Main class that extends the generated MainParser class.

Custom Class Extending Generated Class

package examples.dustin.commandline.jcommando;

import static java.lang.System.out;

/**
 * Demonstrates JCommando-based parsing of command-line
 * arguments from Java code.
 */
public class Main extends MainParser
{
   private String file;
   private boolean verbose;

   @Override
   public void setFile(final String newFilePathAndName)
   {
      file = newFilePathAndName;
   }

   @Override
   public void setVerbose()
   {
      verbose = true;
   }

   public static void main(final String[] arguments)
   {
      final Main instance = new Main();
      instance.parse(arguments);
   }

   /**
    * Called by parser to execute the 'command'.
    */
   public void doExecute()
   {
      out.println("File path/name is " + file + " and verbosity is " + verbose);
   }
}

As shown in the custom Main.java source code shown above, the "parsing" stage is accomplished in JCommando via execution of the parse(String[]) method inherited from the class that JCommando generated based on the configuration XML (and that generated class gets its definition of that parse method from its parent JCommandParser class).

The custom class that extends the generated class needed to have the "set" methods for the options implemented. With these properly implemented, the "interrogation" stage in JCommando-based applications is as simple as accessing the fields set by those custom implemented "set" methods. This was demonstrated in the doExecute() method shown in the last code listing. That doExecute method was generated as an abstract method in the generated parent class because of the specification of the <commandless> element with id of "execute" in the configuration XML.

The JCommandParser class that the custom class ultimately extends has a method printUsage() that can be used to write "help"/"usage" output to standard output. This can be seen in the source code for Main.java available on GitHub.

The next two screen snapshots demonstrate execution of the sample code discussed in this post. The first screen snapshot shows the "usage information that can be automatically printed, in this case when the required "file" option was not specified. The second screen snapshot demonstrates the combinations of long and short option names for the "vile" and "verbose" options.

The steps involved with using JCommando that have been discussed in this blog post are summarized here.

  1. Define options in XML file.
  2. Generate Java parser source code from XML using one of two approaches.
    • Use jcomgen tool provided in JCommando's bin directory.
    • Use Ant target with JCommand-provided Ant task as demonstrated in this post.
  3. Write Java class that extends generated parser class.

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

  • JCommando is open source and available under the zlib/libpng License (Zlib).
  • The jcommando.jar JAR is approximately 27 KB in size and there is no third-party dependency.
  • Defining options in JCommando via XML is a different approach than the other libraries covered in this series, but what I find more interesting about JCommando's options definition is the easy ability to express relationships between options such as "and", "or", "xor", and nested combinations of these.

JCommando implements some novel concepts in terms of Java-based command line options parsing. It requires XML configuration of the potential command line options, but makes it easy to establish relationships between those options. JCommando generates Java source from the XML options configuration and a custom parsing class extends that generated class. JCommando is also the first of the libraries covered in this series to use the Zlib license.

Additional References

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