Skip to content

Picocli 3.6.0

Compare
Choose a tag to compare
@remkop remkop released this 12 Sep 13:03

Picocli 3.6.0

The picocli community is pleased to announce picocli 3.6.0.

This release contains new features, bugfixes and enhancements.

New interface: IDefaultProvider allows you to get default values from a configuration file or some other central place.

@Command Methods: From this release, methods can be annotated with @Command. The method parameters provide the command options and parameters.

Internationalization: from this release, usage help message sections and the description for options and positional parameters can be specified in a resource bundle. A resource bundle can be set via annotations and programmatically.

The error message on invalid user input has been improved.

This release also contains various improvements the the bash/zsh completion script generation to be more consistent with standard completion on these shells.

Many thanks to the many members of the picocli community who raised issues and contributed solutions!

This is the thirty-nineth public release.
Picocli follows semantic versioning.

Table of Contents

New and Noteworthy

Default Provider

This release allows you to specify a default provider in the @Command annotation:

@Command(defaultValueProvider = MyDefaultProvider.class)
class MyCommand // ...

The default provider allows you to get default values from a configuration file or some other central place.
Default providers need to implement the picocli.CommandLine.IDefaultValueProvider interface:

public interface IDefaultValueProvider {

    /**
     * Returns the default value for an option or positional parameter or {@code null}.
     * The returned value is converted to the type of the option/positional parameter
     * via the same type converter used when populating this option/positional
     * parameter from a command line argument.
     *
     * @param argSpec the option or positional parameter, never {@code null}
     * @return the default value for the option or positional parameter, or {@code null} if
     *       this provider has no default value for the specified option or positional parameter
     * @throws Exception when there was a problem obtaining the default value
     */
    String defaultValue(ArgSpec argSpec) throws Exception;
}

@Command Methods

From picocli 3.6, methods can be annotated with @Command. The method parameters provide the command options and parameters. For example:

class Cat {
    public static void main(String[] args) {
        CommandLine.invoke("cat", Cat.class, args);
    }

    @Command(description = "Concatenate FILE(s) to standard output.",
             mixinStandardHelpOptions = true, version = "3.6.0")
    void cat(@Option(names = {"-E", "--show-ends"}) boolean showEnds,
             @Option(names = {"-n", "--number"}) boolean number,
             @Option(names = {"-T", "--show-tabs"}) boolean showTabs,
             @Option(names = {"-v", "--show-nonprinting"}) boolean showNonPrinting,
             @Parameters(paramLabel = "FILE") File[] files) {
        // process files
    }
}

The usage help of the above command looks like this:

Usage: cat [-EhnTvV] [FILE...]
Concatenate FILE(s) to standard output.
      [FILE...]
  -E, --show-ends
  -h, --help               Show this help message and exit.
  -n, --number
  -T, --show-tabs
  -v, --show-nonprinting
  -V, --version            Print version information and exit.

See below for an example that uses a resource bundle to define usage help descriptions outside the code.

For positional parameters, the @Parameters annotation may be omitted on method parameters.

TIP: If compiled with the -parameters flag on Java 8 or higher, the paramLabel of positional parameters is obtained from the method parameter name using reflection instead of the generic arg0, arg1, etc.

Subcommand Methods

If the enclosing class is annotated with @Command, method commands are added as subcommands to the class command, unless the class command has attribute @Command(addMethodSubcommands = false).
For example:

@Command(name = "git", mixinStandardHelpOptions = true, version = "picocli-3.6.0")
class Git {
    @Option(names = "--git-dir", descriptionKey = "GITDIR")
    Path path;

    @Command
    void commit(@Option(names = {"-m", "--message"}) String commitMessage,
                @Option(names = "--squash", paramLabel = "<commit>") String squash,
                @Parameters(paramLabel = "<file>") File[] files) {
        // ... implement business logic
    }
}

Use @Command(addMethodSubcommands = false) on the class @Command annotation if the @Command-annotated methods in this class should not be added as subcommands.

The usage help of the git commit command looks like this:

Usage: git commit [--squash=<commit>] [-m=<arg0>] [<file>...]
      [<file>...]
      --squash=<commit>
  -m, --message=<arg0>

Internationalization

From version 3.6, usage help message sections and the description for options and positional parameters can be specified in a resource bundle. A resource bundle can be set via annotations and programmatically.

Annotation example:

@Command(name = "i18n-demo", resourceBundle = "my.org.I18nDemo_Messages")
class I18nDemo {}

Programmatic example:

@Command class I18nDemo2 {}

CommandLine cmd = new CommandLine(new I18nDemo2());
cmd.setResourceBundle(ResourceBundle.getBundle("my.org.I18nDemo2_Messages"));

Resources for multiple commands can be specified in a single ResourceBundle. Keys and their value can be shared by multiple commands (so you don't need to repeat them for every command), but keys can be prefixed with fully qualified command name + "." to specify different values for different commands. The most specific key wins.

This is especially convenient for @Command methods where long description annotations would make the code less easy to read.

You can use a resource bundle to move the descriptions out of the code:

# shared between all commands
help = Show this help message and exit.
version = Print version information and exit.

# command-specific strings
git.usage.description = Version control system
git.GITDIR = Set the path to the repository

git.commit.usage.description = Record changes to the repository
git.commit.message = Use the given <msg> as the commit message.
git.commit.squash = Construct a commit message for use with rebase --autosquash.
git.commit.<file>[0..*] = The files to commit.

With this resource bundle, the usage help for the above git commit command looks like this:

Usage: git commit [--squash=<commit>] [-m=<arg0>] [<file>...]
Record changes to the repository
      [<file>...]         The files to commit.
      --squash=<commit>   Construct a commit message for use with rebase
                            --autosquash.
  -m, --message=<arg0>    Use the given <msg> as the commit message.

Improved Error Messages

The error messages on invalid input have been improved. For example:

Previously, if an argument could not be converted to a primitive type, the error looked like this:

Could not convert 'abc' to int for option '-num': java.lang.NumberFormatException: For input string: \"abc\"

The new error message for primitive types looks like this:

Invalid value for option '-num': 'abc' is not an int

Previously, if an argument could not be converted to an enum, the error looked like this:

Could not convert 'xyz' to TimeUnit for option '-timeUnit': java.lang.IllegalArgumentException: No enum constant java.util.concurrent.TimeUnit.xyz

The new error message for enums looks like this:

Invalid value for option '-timeUnit': expected one of [NANOSECONDS, MILLISECONDS, MICROSECONDS, SECONDS, MINUTES, HOURS, DAYS] but was 'xyz'

Fixed issues

  • [#321] API: Add support for IDefaultValueProvider. Thanks to Nicolas MASSART for the pull request.
  • [#416] API: Added support for @Command annotation on methods (in addition to classes). Thanks to illes for the pull request.
  • [#433] API: Added method printHelpIfRequested that accepts a ColorScheme parameter. Thanks to Benny Bottema for the suggestion.
  • [#441] API: Added hideParamSyntax attribute to @Option and @Parameters to allow suppressing usage syntax decorations around the param label. Thanks to Benny Bottema for the pull request.
  • [#22], [#415], [#436] API: Added internationalization and localization support via resource bundles.
  • [#473] Enhancement: Improved error messages for invalid input.
  • [#461] Bugfix: Script auto-completion only suggests options and never default bash completions. Thanks to David Walluck for the pull request.
  • [#466] Bugfix: Script auto-completion should not generate suggestions for options with arguments that have no known completions. Thanks to David Walluck for the pull request.
  • [#470] Bugfix: Script auto-completion should generate suggestions for short options with arguments. Thanks to David Walluck for the pull request.
  • [#444] Bugfix: Usage help shows duplicate aliases if registered with same alias multiple times.
  • [#452] Doc: Add UML class diagrams to picocli Javadoc.
  • [#475] Doc: Renamed module examples to picocli-examples.
  • [#478] Doc: Add convenience API example to CommandLine class Javadoc.

Deprecations

No features were deprecated in this release.

Potential breaking changes

The error message displayed on invalid input is different from previous releases. This may break unit tests that expect an exact error message.