JCLAP: Java Command-Line Argument Parser
Copyright © 2009-2020 Giles Winstanley
Version: 2.2
Usage: java snaq.util.jclap.example.ParserExample <options> <file> [<file>] ...
Options:
-w,--width <integer> (mandatory)
Width of resized images.
-h,--height <integer> (mandatory)
Height of resized images.
-d,--dir <folder>
Output directory for resized images.
-f,--format <string>
Allowed values: { "jpg", "png" }
Output format of images.
-v,--verbose
Displays extra runtime information.
-@,--version
Displays the application version information.
-?,--help
Displays help information.
Example application help/usage message created by JCLAP.
What is it?
Command-line applications are very useful for getting things done, particularly when time is critical. Designing and developing a graphical user interface (GUI) for an application is often a lengthy and tedious process, and a large number of applications have no need for an interface so complicated. That said, the interface part is very important, and when an application needs to be run from the command-line, it helps enormously if it has been made simple to use. That's where JCLAP becomes useful. JCLAP helps Java developers to create simple-to-use command-line interfaces for their applications.
For example, if you wanted to write an application to process text files, you might imagine issuing a command such as:
java -jar Application.jar --folder ../foo --type xml
Or perhaps using short versions of the options:
java -jar Application.jar -f ../foo -t xml
This utility allows you to easily parse all these command-line arguments, retrieve the values assigned, and even semi-automatically display help information about the available arguments. The primary aim is to parse command-line argument in the POSIX standard, which is what most end users will already recognise. In addition JCLAP supports long names for options, and an option to stop argument parsing, in the style of the GNU standard. JCLAP takes this hybrid approach to provide a highly flexible way to specify arguments.
Licence Agreement
JCLAP is available under a BSD-style licence as described below. This licence permits redistribution of the binary or source code (or both) for commercial or non-commercial use, provided the licence conditions are followed to acknowledge origination and authorship of the library.
| JCLAP: Java Command-Line Argument Parser <https://www.snaq.net/software/jclap/> Copyright (c) 2009-2020 Giles Winstanley. All Rights Reserved. |
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Where can I get it?
The simplest way is using Apache Maven, adding the following details to your POM file's dependencies section:
<dependency>
<groupId>net.snaq</groupId>
<artifactId>jclap</artifactId>
<version>2.2</version>
</dependency>
Otherwise you can download JCLAP using the following links:
You can download the latest version of JCLAP from: https://www.snaq.net/software/jclap/
JCLAP requires Java Platform 8 or greater installed. The JAR also includes module support for Java 9+ (module name: net.snaq.jclap).
What about support?
Send all queries/issues/requests here, including as much information as possible to help diagnose the problem (e.g. stacktraces, etc.). The library includes basic CLI translations for a few European languages (en/fr/de/es/pt), and chooses based on the default system locale. However, given my limited grasp of non-English technical jargon, some of the translations may be incorrect. Please contact me if you know more accurate translations for the terms, or want to provide another translation.
Usage
|
JCLAP is simple to use, but it's recommended to follow certain guidelines to make the flow of your application predictable for end users. The basic rules for specifying options are shown in the table above. If you know the POSIX and GNU standards, then you'll quickly recognise how they operate, and even if not you may be familiar with the patterns. The easiest way to demonstrate is with a real-world example.
Imagine a hypothetical application for resizing images to specified width/height dimensions, writing the resized image files to a specified folder/directory, in either JPEG or PNG image format. The user might choose to have information output to the console during processing if required, and there should also be a usage message to show how the basics of how the application may be run. The following code provides all this functionality, including error-checking of arguments, etc. This example doesn't cover all the available methods for creating/using options, but gives a good example of likely use for such a scenerio. For more information see the Javadoc documentation.
import java.util.List;
import snaq.util.jclap.*;
/**
* Example usage of {@link CLAParser} class, showing how options may be added,
* parsed, and referenced, along with a recommended exception-handling strategy.
*/
public class ParserExample
{
private ParserExample() {}
public static void main(String[] args) throws OptionException
{
// Create an instance of the parser class.
final CLAParser parser = new CLAParser();
// Define string to describe the non-option arguments in the usage message.
final String extraArgs = "<file> [<file>] ...";
// Arguments:
// -w/--width : mandatory, single
// -h/--height : optional, single
// -d/--dir : mandatory, single
// -f/--format : mandatory, single, enum{"jpg", "png"}
// -v/--verbose : optional, multiple
// -@/--version : optional, single
// -?/--help : optional, single
// Note: a reference to an Option instance may be retained in a variable,
// or simply added & retrieved by name (which is generally easier).
final Option<Integer> oWidth = parser.addIntegerOption("w", "width", "Width of resized images.", true, false);
parser.addIntegerOption("h", "height", "Height of resized images.", false, false);
parser.addStringOption("d", "dir", "Output directory for resized images.", true, false);
parser.addEnumStringOption("f", "format", "Output format of images.", true, false, new String[]{"jpg", "png"});
parser.addBooleanOption("v", "verbose", "Displays extra runtime information.", true);
parser.addBooleanOption("@", "version", "Displays the application version information.", false);
parser.addBooleanOption("?", "help", "Displays help information.", false);
try
{
// Parse the command-line arguments into options.
parser.parse(args);
// Check for display of version information.
// This checks a boolean/flag option value, with an specified default value.
if (parser.getBooleanOptionValue("@", false))
System.out.printf("Version: %s%n", "1.2.3");
// Check for help option, and display if requested.
// This checks the boolean/flag option values, with an assumed default value (false).
if (parser.getBooleanOptionValue("?") || args.length == 0)
{
// Usage message is generated automatically from the defined options.
// The three last argument define:
// 1. application launch command
// 2. extra (non-option) arguments
// 3. extra (non-option) information
parser.printUsage(System.out, true, null, extraArgs, null);
System.exit(0);
}
// Get resized image dimensions.
// Don't care about a default value, as options are mandatory.
final Integer imageW = parser.getOptionValue(oWidth, null); // Get by object reference.
final Integer imageH = parser.getIntegerOptionValue("h", null); // Get by short name.
// Check for verbose option, and see how verbose user wants.
// Get typed option value by long name.
final List<Boolean> lVerbose = parser.getBooleanOptionValues("verbose");
final int verbosity = lVerbose.size();
if (verbosity > 0)
System.out.printf("Width:%d, Height:%d%n", imageW, imageH);
// Get folder.
final String dir = parser.getStringOptionValue("dir", ".");
// Get output image format.
// EnumeratedString option is retrieved with string-typed method.
final String format = parser.getStringOptionValue("format", "jpg");
if (verbosity > 0)
System.out.printf("Image format: %s%n", format);
// Display arguments not related to any defined options.
if (verbosity > 0)
{
for (String s : parser.getNonOptionArguments())
System.out.printf("Unknown argument: %s%n", s);
}
// Output specified options.
System.out.printf("width : %d%n", imageW);
System.out.printf("height : %d%n", imageH);
System.out.printf("dir : %s%n", dir);
System.out.printf("format : %s%n", format);
System.out.printf("verbose: %b (%d)%n", verbosity > 0, verbosity);
}
catch (OptionException ox)
{
try
{
// If help required, print usage message.
if (parser.getBooleanOptionValue("?") || args.length == 0)
{
parser.printUsage(System.out, true, null, extraArgs, null);
System.exit(0);
}
System.err.println(ox.getMessage());
parser.printUsage(System.out, false, null, extraArgs, null);
System.exit(1);
}
catch (OptionException ox2)
{
ox2.printStackTrace();
}
}
}
}
Creating your own option types
JCLAP also makes it straightforward to provide your own custom option types, if the built-in ones are not sufficient for your needs. As an example of how to create your own, take a look at the source code for the snaq.util.jclap.LocalDateOption class shown below, which provides a basic implementation to parse a LocalDate value according to the default locale.
package snaq.util.jclap;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
/**
* Option implementation for specifying date values.
*/
public class LocalDateOption extends Option<LocalDate>
{
private DateTimeFormatter dtf = null;
public LocalDateOption(String shortName, String longName, String description, boolean mandatory, boolean allowMany)
{
super(shortName, longName, description, true, mandatory, allowMany);
}
public LocalDateOption(String shortName, String longName, String description, int minCount, int maxCount)
{
super(shortName, longName, description, true, minCount, maxCount);
}
@Override
public Class<LocalDate> getType()
{
return LocalDate.class;
}
protected LocalDate parseValue(String arg, Locale locale) throws OptionException
{
if (arg == null)
throw new OptionException(OptionException.Type.ILLEGAL_OPTION_VALUE, this, arg);
try
{
final DateTimeFormatter df = (dtf != null) ?
dtf.withLocale(locale) :
DateTimeFormatter.ISO_LOCAL_DATE.withLocale(locale);
return LocalDate.parse(arg, df);
}
catch (DateTimeParseException px)
{
throw new OptionException(OptionException.Type.ILLEGAL_OPTION_VALUE, this).withCause(px);
}
}
public void setDateFormat(DateTimeFormatter dtf)
{
this.dtf = dtf;
}
public DateTimeFormatter getDateFormat(Locale locale)
{
if (dtf != null)
return dtf.withLocale(locale);
return DateTimeFormatter.ISO_LOCAL_DATE.withLocale(locale);
}
}
Notes
Strange characters on command-line
Some people are confused when trying to use "non-standard" (e.g. accented) characters in command-line applications, as non-English messages often show up with unexpected and/or garbled characters. Java supports the Unicode UTF-8 character set well, but many operating systems launch command-line utilities using the platform's default character/file encoding, and to complicate matters each terminal application has differing support for these encodings. These are some possible ways to help work around this:
- Ensure you use a UTF-8 compliant terminal shell
- Use an extra launch parameter:
java -Dfile.encoding=UTF-8 ... - Set an environmental variable:
JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8
Other libraries
JCLAP is by no means unique, and many similar utilities are available both for free and commercially. JCLAP was originally written to fulfil a specific need, then simply evolved as time passed, and it's proved useful in many applications. 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.
Other command-line argument parsing software:
- picocli
- Apache Commons CLI
- JOpt Simple
- args4j
- JArgs
- JCommander
- CmdLn
- cli-parser
- JewelCli
- ripopt
- CLAJR
- parse-cmd
- JCommando
- JSAP
- GNU getopt (Java port)
- argparser
Unsurprisingly I take no responsibility for the quality, or lack thereof, of the software provided via the links above.
Change log
| 2020-09-12 (v2.2) |
|
|---|---|
| 2019-02-21 (v2.1) |
|
| 2018-12-04 (v2.0) |
|
| 2017-10-26 (v1.5) |
|
| 2015-10-01 (v1.4) |
|
| 2015-04-29 (v1.3) |
|
| 2013-11-09 (v1.2) |
|
| 2012-02-29 (v1.1.1) |
|
| 2011-07-05 (v1.1) |
|