picocli 3.2.0
Picocli 3.2.0
The picocli community is pleased to announce picocli 3.2.0.
This release contains new features and enhancements:
- Improved support for Dependency Injection
- Methods can now be annotated with
@Option
and@Parameters
- Support for JLine-based interactive command line interfaces (
completionCandidates
attribute on@Option
and@Parameters
, and theAutoComplete.complete
method) - New
@Spec
annotation for injecting a command with itsCommandSpec
This is the thirty-third public release.
Picocli follows semantic versioning.
Table of Contents
New and Noteworthy
Dependency Injection
This release makes integration with Dependency Injection containers extremely easy:
CommandLine
constructor now accepts aClass
instance as the user object, and will delegate to theIFactory
to get an instance.- New
CommandLine.run(Class<Runnable>, IFactory, ...)
andCommandLine.call(Class<Callable>, IFactory, ...)
methods. These work the same as the existingrun
andcall
methods except that theRunnable
orCallable
instance is created by the factory.
The below example shows how to create an IFactory
implementation with a Guice Injector
:
import com.google.inject.*;
import picocli.CommandLine.IFactory;
public class GuiceFactory implements IFactory {
private final Injector injector = Guice.createInjector(new DemoModule());
@Override
public <K> K create(Class<K> aClass) throws Exception {
return injector.getInstance(aClass);
}
static class DemoModule extends AbstractModule {
@Override
protected void configure() {
bind(java.util.List.class).to(java.util.LinkedList.class);
bind(Runnable.class).to(InjectionDemo.class);
}
}
}
Use the custom factory when creating a CommandLine
instance, or when invoking the run
or call
convenience methods:
import javax.inject.Inject;
@Command(name = "di-demo")
public class InjectionDemo implements Runnable {
@Inject java.util.List list;
// @Option(names = "-x") int x; // add options etc as needed...
public static void main(String[] args) {
CommandLine.run(Runnable.class, new GuiceFactory(), args);
}
@Override
public void run() {
assert list instanceof java.util.LinkedList;
}
}
Annotated Methods
From this release, @Option
and @Parameter
annotations can be added to methods as well as fields of a class.
For concrete classes, annotate "setter" methods (methods that accept a parameter) and when the option is specified on the command line, picocli will invoke the method with the value specified on the command line, converted to the type of the method parameter.
Alternatively, you may annotate "getter-like" methods (methods that return a value) on an interface, and picocli will create an instance of the interface that returns the values specified on the command line, converted to the method return type. This feature is inspired by Jewel CLI.
Annotating Methods of an Interface
The @Option
and @Parameters
annotations can be used on methods of an interface that return a value. For example:
interface Counter {
@Option(names = "--count")
int getCount();
}
You use it by specifying the class of the interface:
CommandLine cmd = new CommandLine(Counter.class); // specify a class
String[] args = new String[] {"--count", "3"};
cmd.parse(args);
Counter counter = cmd.getCommand(); // picocli created an instance
assert counter.getCount() == 3; // method returns command line value
Annotating Methods of a Concrete Class
The @Option
and @Parameters
annotations can be used on methods of a class that accept a parameter. For example:
class Counter {
int count;
@Option(names = "--count")
void setCount(int count) {
this.count = count;
}
}
You use it by passing an instance of the class:
Counter counter = new Counter(); // the instance to populate
CommandLine cmd = new CommandLine(counter);
String[] args = new String[] {"--count", "3"};
cmd.parse(args);
assert counter.count == 3; // method was invoked with command line value
JLine Tab-Completion Support
This release adds support for JLine Tab-Completion.
Jline 2.x and 3.x is a Java library for handling console input, often used to create interactive shell applications.
Command line applications based on picocli can generate completion candidates for the command line in the JLine shell. The generated completion candidates are context sensitive, so once a subcommand is specified, only the options for that subcommand are shown, and once an option is specified, only parameters for that option are shown.
Below is an example picocli Completer
implementation for JLine 2.x:
import jline.console.completer.ArgumentCompleter;
import jline.console.completer.Completer;
import picocli.AutoComplete;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
import java.util.List;
public class PicocliJLineCompleter implements Completer {
private final CommandSpec spec;
public PicocliJLineCompleter(CommandSpec spec) {
this.spec = spec;
}
@Override
public int complete(String buffer, int cursor, List<CharSequence> candidates) {
// use the jline internal parser to split the line into tokens
ArgumentCompleter.ArgumentList list =
new ArgumentCompleter.WhitespaceArgumentDelimiter().delimit(buffer, cursor);
// let picocli generate completion candidates for the token where the cursor is at
return AutoComplete.complete(spec,
list.getArguments(),
list.getCursorArgumentIndex(),
list.getArgumentPosition(),
cursor,
candidates);
}
}
Completion Candidates
From this release, @Options
and @Parameters
have a new completionCandidates
attribute that can be used to generate a list of completions for this option or positional parameter. For example:
static class MyAbcCandidates extends ArrayList<String> {
MyAbcCandidates() { super(Arrays.asList("A", "B", "C")); }
}
class ValidValuesDemo {
@Option(names = "-o", completionCandidates = MyAbcCandidates.class)
String option;
}
This will generate completion option values A
, B
and C
in the generated bash auto-completion script and in JLine.
${DEFAULT-VALUE}
Variable
From picocli 3.2, it is possible to embed the default values in the description for an option or positional parameter by
specifying the variable ${DEFAULT-VALUE}
in the description text.
Picocli uses reflection to get the default values from the annotated fields.
The variable is replaced with the default value regardless of the @Command(showDefaultValues)
attribute
and regardless of the @Option(showDefaultValues)
or @Parameters(showDefaultValues)
attribute.
class DefaultValues {
@Option(names = {"-f", "--file"},
description = "the file to use (default: ${DEFAULT-VALUE})")
File file = new File("config.xml");
}
CommandLine.usage(new DefaultValues(), System.out);
This produces the following usage help:
Usage: <main class> -f=<file>
-f, --file=<file> the file to use (default: config.xml)
${COMPLETION-CANDIDATES}
Variable
Similarly, it is possible to embed the completion candidates in the description for an option or positional parameter by
specifying the variable ${COMPLETION-CANDIDATES}
in the description text.
This works for java enum
classes and for options or positional parameters of non-enum types for which completion candidates are specified.
enum Lang { java, groovy, kotlin, javascript, frege, clojure }
static class MyAbcCandidates extends ArrayList<String> {
MyAbcCandidates() { super(Arrays.asList("A", "B", "C")); }
}
class ValidValuesDemo {
@Option(names = "-l", description = "Enum. Values: ${COMPLETION-CANDIDATES}")
Lang lang = null;
@Option(names = "-o", completionCandidates = MyAbcCandidates.class,
description = "Candidates: ${COMPLETION-CANDIDATES}")
String option;
}
CommandLine.usage(new ValidValuesDemo(), System.out);
This produces the following usage help:
Usage: <main class> -l=<lang> -o=<option>
-l=<lang> Enum. Values: java, groovy, kotlin, javascript, frege, clojure
-o=<option> Candidates: A, B, C
@Spec
Annotation
A new @Spec
annotation is now available that injects the CommandSpec
model of the command into a command field.
This is useful when a command needs to use the picocli API, for example to walk the command hierarchy and iterate over its sibling commands.
This complements the @ParentCommand
annotation; the @ParentCommand
annotation injects a user-defined command object, whereas this annotation injects a picocli class.
class InjectSpecExample implements Runnable {
@Spec CommandSpec commandSpec;
//...
public void run() {
// do something with the injected spec
}
}
Lenient Parse Mode
This release adds the ability to continue parsing invalid input to the end.
When collectErrors
is set to true
, and a problem occurs during parsing, an Exception
is added to the ParseResult.errors()
list and parsing continues. The default behaviour (when collectErrors
is false
) is to abort parsing by throwing the Exception
.
This is useful when generating completion candidates on partial input, and is also useful when using picocli in
languages like Clojure where idiomatic error handling does not involve throwing and catching exceptions.
When using this feature, applications are responsible for actively verifying that no errors occurred before executing the business logic. Use with care!
Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
Fixed issues
- [#182] New Feature: Add support for annotating methods with
@Option
and@Parameters
. - [#393] New feature: Add support for JLine completers.
- [#389] New feature: Support 'lenient' parsing mode: don't throw
Exceptions
but add them to theParseResult.errors()
list and continue parsing. - [#392] New feature: Ability to map command line arguments to picocli spec elements. Internally used for generating completion candidates.
- [#391] New feature: Add API to get completion candidates for option and positional parameter values of any type.
- [#395] New feature: Allow embedding default values anywhere in description for
@Option
or@Parameters
. - [#259] New Feature: Added
@Spec
annotation to injectCommandSpec
into application field. - [#400] Enhancement: Add run/call static methods that accept an
IFactory
. This allows Dependency Injection containers to provide the Runnable/Callable implementation. - [#404] Enhancement: Ask IFactory for implementation before creating Proxy for interface. Needed for Dependency Injection.
- [#398] Enhancement: Allow
@PicocliScript
annotation on Groovy script@Field
variables instead of just on imports. - [#322] Enhancement: Add
defaultValue
attribute to @option and @parameters annotation. - [#375] Enhancement: Improve
ParameterIndexGapException
error message. Thanks to gpettey. - [#405] Enhancement: Add method
CommandLine.getUsageMessage()
. - [#406] Enhancement: Added fields to
ParameterException
. Thanks to David Hait. - [#401] Doc: The user manual no longer includes the full
CommandLine.java
source code.
Deprecations
No features were deprecated in this release.
Potential breaking changes
This release has no breaking changes.