Monday, August 7, 2017

Java Command-Line Interfaces (Part 10): picocli

The main picocli page describes picocli as "a mighty tiny command line interface" that "is a one-file Java framework for parsing command line arguments and generating polished, easily tailored usage help messages. With colors." This post provides a brief overview of applying Picocli 0.9.7 to process command line arguments in Java code.

Like the other Java-based command line processing libraries covered in this series, picocli is open source. Because all of picocli's implementation exists in a single Java source code file, it's easy to use the source directly if desired. The picocli page emphasizes this, "A distinguishing feature of picocli is how it aims to let users run picocli-based applications without requiring picocli as an external dependency: all the source code lives in a single file, to encourage application authors to include it in source form." If you'd rather use picocli as a library, there is a JAR available on the Maven Repository with the numerous compiled .class files (Picocli features one Java file but with numerous nested classes and annotations).

The easiest approach for getting an idea of Picocli's single-file nature is to look at that single file itself. The Java source code for CommandLine.java is available on the Picocli 'download' page. The next two screen snapshots show some output from javap when executed against the CommandLine class and when executed against one its inner annotations and one of its inner classes.

Whether one compiles CommandLine.java into one's own class/JAR file or one chooses to use a pre-built JAR from Maven, the source code of an application using Picocli is obviously the same. The "definition" stage of parsing with Picocli is accomplished by annotating instance fields that will store values associated with command-line options. This is demonstrated in the code snippet below.

"Definition" Stage with Picocli

/**
 * Demonstrate Java-based command-line processing with picocli.
 */
@Command(
   name="Main",
   description="Demonstrating picocli",
   headerHeading="Demonstration Usage:%n%n")
public class Main
{
   @Option(names={"-v", "--verbose"}, description="Verbose output?")
   private boolean verbose;

   @Option(names={"-f", "--file"}, description="Path and name of file", required=true)
   private String fileName;

   @Option(names={"-h", "--help"}, description="Display help/usage.", help=true)
   boolean help;

The code sample just shown demonstrates that Picocli allows for multiple names of the option flags to be specified (I specified single-hyphen single-character names and double hyphen multi-character names in my example). The example also shows that required=true can be specified for required options and help=true can be specified for "help" options that support special help-specific behaviors such as printing usage details and avoiding errors related to absent required options. Note that Picocli 0.9.8 adds more specific help type support with versionHelp and usageHelp.

The "parsing" stage is accomplished in Picocli with CommandLine.populateCommand(T, String...), where the T is the instance of the class with Picocli-annotated fields and the remaining Strings are the arguments to be parsed. This is demonstrated in the next code snippet.

"Parsing" Stage with Picocli

final Main main = CommandLine.populateCommand(new Main(), arguments);

The "interrogation" stage with Picocli consists simply of accessing the Picocli-annotated fields of the instance passed to the CommandLine.populateCommand(T,String...) method in the "parsing" stage. A simple example of this "interrogation" is depicted in the next code listing.

"Interrogation" Stage with Picocli

out.println(
     "The provided file path and name is " + main.fileName
   + " and verbosity is set to " + main.verbose);

To display help/usage information to the user when -h or --help is provided on the command line, it's as simple as "interrogating" the Picocli-annotated field that was designated help=true to see if that boolean is set or not and, if it is set, calling one of the overloaded CommandLine.usage methods. I happened to use one of the static versions of this method as shown in the next code listing.

Help/Usage with Picocli

if (main.help)
{
   CommandLine.usage(main, out, CommandLine.Help.Ansi.AUTO);
}

The next few screen snapshots demonstrate the simple Picocli-based processing application in action. The first image shows the type of error message and stack trace presented when a required flag is not present. The second image shows how the long and short names I specified in the annotations are respected. The third image shows the help feature in action.

One of Picocli's optional features that many of the other Java-based command-line parsing libraries don't have is color syntax support. The first code listing in this post showed some strings defined in annotations with @| |@ syntax. In the screen snapshot demonstrating "help" usage above, these characters were passed through as-is with no special treatment. However, if I instead run this sample code in Cygwin, I see what those tokens accomplish.

From the above screen snapshot, we see that Picocli applied some color syntax (yellow and white) automatically to the individual options' help and that it also applied the customized bold and underlined bold syntax to help description areas where the @| |@ syntax was applied.

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

  • Picocli is open source and is licensed under the Apache License 2.0.
  • Picocli does not require any third-party libraries or frameworks to be downloaded.
    • Picocli source code is completely contained within a single .java file and that source can be copied and pasted into one's own configuration management system and built with the rest of the application code, meaning that even a Picocli JAR file is not strictly necessary.
  • The CommandLine.java source code file (Picocli 0.9.7) is just under 3700 lines (including white space and comments) and is almost 200 KB in size. The picocli-0.9.7.jar file is approximately 83 KB in size.
  • Picocli enjoys current and frequent support. Its 0.9.8 version was released yesterday (after I had written most of this post).
  • Picocli documentation is detailed and in many ways more modern-feeling than the documentation for several other Java-based command-line processing libraries.
  • Picocli support for color syntax is easy to use and support for color syntax on different platforms is documented under the "Supported Platforms" section of the documentation.
  • Picocli's use of annotations on instance-level fields is similar to some of the other Java-based command-line processing libraries and enjoys the same advantages.
  • Basic Picocli features are highly approachable and easy to learn quickly, but Picocli also supports the ability to significantly customize several aspects of command-line processing with Picocli.

The code listings shown in this post are available in complete form on GitHub.

Picocli is a currently supported and updated library for processing command line arguments from Java. It features several of the newer features and approaches of some of the other available Java-based command-line processing libraries and throws in a couple differentiating features (color syntax and entire library encapsulated in single Java source file). Picocli is easy enough to use and appealing in its own right, but is most likely to separate itself from others in a particular developer's opinion if that developer desires the color syntax support or the ability to drop the source code file into the developer's project without any need for a JAR or compiled .class file.

Additional References

1 comment:

Unknown said...

Thank you for your quick action fixing the screenshots that showed markup!

I like the article a lot. If I can make one more suggestion, I was a bit confused by the "easiest approach for getting an idea" paragraph and the javap screenshots; not sure what purpose these serve. Sometimes less is more, I would consider removing them. I hope you don't think I'm too forward.

Overall it is a great article in a great series and I'm proud and glad picocli is part of the series!

What do you think of the new autocomplete feature? Do you think it's interesting enough to warrant a follow-up post?