Picocli 4.0.0
Picocli 4.0.0 GA
The picocli community is pleased to announce picocli 4.0. This is a big release.
First, the picocli-codegen
module now includes an annotation processor that instantly enables your JAR for GraalVM native images. It also gives compile-time errors for invalid annotations and attributes. We recommend that all projects using picocli enable this annotation processor.
The execute
API is an easy way to execute your command with almost no code. It allows for more flexible configuration than previous APIs, and introduces much improved exit code support. This replaces the static methods call
and run
, as well as the parseWithHandlers
methods, which are now deprecated.
Improved Spring support: the new picocli-spring-boot-starter
module includes a PicocliSpringFactory
and auto-configuration to use Spring dependency injection in your picocli command line application. This is especially useful if your application contains subcommands.
The parser has been enhanced to handle argument groups: mutually exclusive options, mutually dependent options, and option sections in the usage help. What makes the picocli design unique and extremely powerful is that argument groups can be nested, so applications can define repeating composite groups of mutually exclusive or co-dependent options.
Annotation attributes can now contain variables that can be resolved as system properties, environment variables and resource bundle keys.
The picocli JAR is now an explicit JPMS module, as well as an OSGi bundle. As part of this change, the Groovy support classes and annotations have been moved to a separate picocli-groovy
artifact.
Boolean options can now easily be made negatable, which adds a "no-" version of the option. This is a common feature in command line parser libraries for Perl, PHP, Ruby, Lisp, Dart and Go, but we are not aware of any other Java libraries that support this.
All in all, this release contains 96 bugfixes and improvements over picocli 3.9.6.
Many thanks to the following community contributors to this release of picocli:
AkosCz, AlcaYezz, Andreas Deininger, andrewbleonard, Arturo Alonso, Bob Tiernay, Devin Smith, feinstein, Garret Wilson, Gerard Bosch, gitfineon, jrevault, Judd Gaddie, Liam Esteban Prince, marinier, Michael D. Adams, Mikaël Barbero, Mikusch, Nicolas Mingo, Paolo Di Tommaso, Philipp Hanslovsky, Radu Cotescu, Reinhard Pointner, Sebastian Thomschke, Shane Rowatt, shanetreacy, Steffen Rehberg, Sualeh Fatehi, Takuya Ishibashi, Thibaud Lepretre and Warkdev.
This is the fifty-seventh public release.
Picocli follows semantic versioning.
Table of Contents
-
- Annotation processor
- Execution API
- Spring Boot support
- Argument groups
- Variable interpolation in annotation attributes
- Explicit JPMS module and OSGi bundle
- New Groovy module
- Negatable options
- Fallback value for options
- Custom parameter processing
- Improved parsing of quoted parameters
- Auto-detect terminal width for usage help
- Improved support for Chinese, Japanese and Korean usage help
-
run
,call
,invoke
, andparseWithHandlers
methods replaced byexecute
CommandLine.setSplitQuotedStrings
deprecatedparse
deprecated in favor ofparseArgs
- Range public fields
-
picocli.groovy
classes moved to separate artifact- Split regex on single-value options is now disallowed
- ColorScheme is now immutable
- Boolean options no longer toggle by default
- ParseResult
matchedOptions
now returns full list - Error message for unmatched arguments changed
- Option order changed
- Factory
New and Noteworthy
Annotation processor
The picocli-codegen
module now includes an annotation processor that instantly enables your JAR for GraalVM native images. The annotation processor can build a model from the picocli annotations at compile time rather than at runtime.
Use this if you’re interested in:
- Compile time error checking. The annotation processor shows errors for invalid annotations and attributes immediately when you compile, instead of during testing at runtime, resulting in shorter feedback cycles.
- Graal native images. The annotation processor generates and updates Graal configuration files under
META-INF/native-image/picocli-generated/$project
during compilation, to be included in the application jar.
This includes configuration files for reflection, resources and dynamic proxies.
By embedding these configuration files, your jar is instantly Graal-enabled.
The$project
location is configurable, see processor options below.
In most cases no further configuration is needed when generating a native image.
Processor option: project
The picocli annotation processor supports a number of options, most important of which is the project
option to control the output subdirectory: the generated files are written to META-INF/native-image/picocli-generated/${project}
. A good convention is to use the Maven ${groupId}/${artifactId}
as the value; a unique subdirectory ensures your jar can be shaded with other jars that may also contain generated configuration files.
To configure this option, pass the -Aproject=<some value>
to the javac compiler. The examples below show how to do this for Maven and Gradle.
Enabling the Annotation Processor
Since Java 6, annotation processing is part of the standard javac
compiler, but many IDEs and build tools require something extra to enable annotation processing.
IDE
This page shows the steps to configure Eclipse and IntelliJ IDEA to enable annotation processing.
Maven
In Maven, use annotationProcessorPaths
in the configuration
of the maven-compiler-plugin
. This requires maven-compiler-plugin
plugin version 3.5 or higher.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- annotationProcessorPaths requires maven-compiler-plugin version 3.5 or higher -->
<version>${maven-compiler-plugin-version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>info.picocli</groupId>
<artifactId>picocli-codegen</artifactId>
<version>4.0.0</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Aproject=${groupId}/${artifactId}</arg>
</compilerArgs>
</configuration>
</plugin>
See the picocli-codegen
README for more details.
Gradle
Use the annotationProcessor
path in Gradle 4.6 and higher:
dependencies {
compile 'info.picocli:picocli:4.0.0'
annotationProcessor 'info.picocli:picocli-codegen:4.0.0'
}
To set an annotation processor option in Gradle, add these options to the options.compilerArgs
list in the compileJava
block.
compileJava {
options.compilerArgs += ["-Aproject=${project.group}/${project.name}"]
}
See the picocli-codegen
README for more details.
Execution API
Picocli 4.0 introduces new API to execute commands. Let’s take a quick look at what changed.
Exit Code
Many command line applications return an exit code to signify success or failure. Zero often means success, a non-zero exit code is often used for errors, but other than that, meanings differ per application.
The new CommandLine.execute
method introduced in picocli 4.0 returns an int
, and applications can use this return value to call System.exit
if desired. For example:
public static void main(String... args) {
CommandLine cmd = new CommandLine(new App());
int exitCode = cmd.execute(args);
System.exit(exitCode);
}
Older versions of picocli had some limited exit code support where picocli would call System.exit
, but this is now deprecated.
Generating an Exit Code
@Command
-annotated classes that implement Callable
and @Command
-annotated methods can simply return an int
or Integer
, and this value will be returned from CommandLine.execute
. For example:
@Command(name = "greet")
class Greet implements Callable<Integer> {
public Integer call() {
System.out.println("hi");
return 1;
}
@Command
int shout() {
System.out.println("HI!");
return 2;
}
}
assert 1 == new CommandLine(new Greet()).execute();
assert 2 == new CommandLine(new Greet()).execute("shout");
Commands with a user object that implements Runnable
can implement the IExitCodeGenerator
interface to generate an exit code. For example:
@Command(name = "wave")
class Gesture implements Runnable, IExitCodeGenerator {
public void run() {
System.out.println("wave");
}
public int getExitCode() {
return 3;
}
}
assert 3 == new CommandLine(new Gesture()).execute();
Exception Exit Codes
By default, the execute
method returns CommandLine.ExitCode.USAGE
(64
) for invalid input, and CommandLine.ExitCode.SOFTWARE
(70
) when an exception occurred in the Runnable, Callable or command method. (For reference, these values are EX_USAGE
and EX_SOFTWARE
, respectively, from Unix and Linux sysexits.h). This can be customized with the @Command
annotation. For example:
@Command(exitCodeOnInvalidInput = 123,
exitCodeOnExecutionException = 456)
Additionally, applications can configure a IExitCodeExceptionMapper
to map a specific exception to an exit code:
class MyMapper implements IExitCodeExceptionMapper {
public int getExitCode(Throwable t) {
if (t instanceof FileNotFoundException) {
return 74;
}
return 1;
}
}
When the end user specified invalid input, the execute
method prints an error message followed by the usage help message of the command, and returns an exit code. This can be customized by configuring a IParameterExceptionHandler
.
If the business logic of the command throws an exception, the execute
method prints the stack trace of the exception and returns an exit code. This can be customized by configuring a IExecutionExceptionHandler
.
Configuration
The new CommandLine.execute
method is an instance method. The older run
, call
and invoke
methods are static methods. Static methods don’t allow configuration. The new API lets applications configure the parser or other aspects before execution. For example:
public static void main(String... args) {
CommandLine cmd = new CommandLine(new App());
cmd.setCaseInsensitiveEnumValuesAllowed(true);
cmd.setUnmatchedArgumentsAllowed(true);
cmd.setStopAtPositional(true);
cmd.setExpandAtFiles(false);
cmd.execute(args);
}
Spring support
Thibaud Lepretre, the author of kakawait/picocli-spring-boot-starter has graciously contributed a pull request to the picocli project with a new picocli-spring-boot-starter
module. This includes a PicocliSpringFactory
and auto-configuration and makes it extremely easy to use Spring dependency injection in your picocli command line application.
Spring Boot example
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Bean;
import picocli.CommandLine;
import picocli.CommandLine.IFactory;
@SpringBootApplication
public class MySpringApp implements CommandLineRunner, ExitCodeGenerator {
private int exitCode;
@Autowired
IFactory factory; // auto-configured to inject PicocliSpringFactory
@Autowired
MyCommand myCommand; // your @picocli.CommandLine.Command-annotated class
@Override
public void run(String... args) {
// let picocli parse command line args and run the business logic
exitCode = new CommandLine(myCommand, factory).execute(args);
}
@Override
public int getExitCode() {
return exitCode;
}
public static void main(String[] args) {
// let Spring instantiate and inject dependencies
System.exit(SpringApplication.exit(SpringApplication.run(MySpringApp.class, args)));
}
}
When your command is annotated with @Component
, Spring can autodetect it for dependency injection.
The business logic of your command looks like any other picocli command with options and parameters.
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import java.util.concurrent.Callable;
@Component
@Command(name = "myCommand")
public class MyCommand implements Callable<Integer> {
@Autowired
private SomeService someService;
// Prevent "Unknown option" error when users use
// the Spring Boot parameter 'spring.config.location' to specify
// an alternative location for the application.properties file.
@Option(names = "--spring.config.location", hidden = true)
private String springConfigLocation;
@Option(names = { "-x", "--option" }, description = "example option")
private boolean flag;
public Integer call() throws Exception {
// business logic here
return 0;
}
}
Argument groups
This release introduces a new @ArgGroup
annotation and its ArgGroupSpec
programmatic equivalent.
Argument Groups can be used to define:
- mutually exclusive options
- options that must co-occur (dependent options)
- option sections in the usage help message
- repeating composite arguments
To create a group using the annotations API, annotate a field or method with @ArgGroup
.
The field's type refers to the class containing the options and positional parameters in the group.
(For annotated interface methods this would be the return type, for annotated setter methods in a concrete class this would be the setter's parameter type.)
Picocli will instantiate this class as necessary to capture command line argument values in the @Option
and @Parameters
-annotated fields and methods of this class.
Mutually Exclusive Options
Annotate a field or method with @ArgGroup(exclusive = true)
to create a group of mutually exclusive options and positional parameters. For example:
@Command(name = "exclusivedemo")
public class MutuallyExclusiveOptionsDemo {
@ArgGroup(exclusive = true, multiplicity = "1")
Exclusive exclusive;
static class Exclusive {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
}
The above example defines a command with mutually exclusive options -a
, -b
and -c
.
The group itself has a multiplicity
attribute that defines how many times the group may be specified within the command.
The default is multiplicity = "0..1"
, meaning that by default a group may be omitted or specified once.
In this example the group has multiplicity = "1"
, so the group must occur once: one of the exclusive options must occur on the command line.
The synopsis of this command is exclusivedemo (-a=<a> | -b=<b> | -c=<c>)
.
Note that the options are defined as required = true
; this means required within the group, not required within the command.
Picocli will validate the arguments and throw a MutuallyExclusiveArgsException
if multiple mutually exclusive arguments were specified. For example:
MutuallyExclusiveOptionsDemo example = new MutuallyExclusiveOptionsDemo();
CommandLine cmd = new CommandLine(example);
try {
cmd.parseArgs("-a=1", "-b=2");
} catch (MutuallyExclusiveArgsException ex) {
assert "Error: -a=<a>, -b=<b> are mutually exclusive (specify only one)"
.equals(ex.getMessage());
}
For the above group, only one of the options can be specified. Any other combination of options, or the absence of options, is invalid.
Mutually Dependent Options
Annotate a field or method with @ArgGroup(exclusive = false)
to create a group of dependent options and positional parameters that must co-occur. For example:
@Command(name = "co-occur")
public class DependentOptionsDemo {
@ArgGroup(exclusive = false)
Dependent dependent;
static class Dependent {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
}
The above example defines a command with dependent options -a
, -b
and -c
that must co-occur.
The group itself has a multiplicity
attribute that defines how many times the group may be specified within the command.
In this example the group uses the default multiplicity, multiplicity = "0..1"
, meaning that the group may be omitted or specified once.
The synopsis of this command is co-occur [-a=<a> -b=<b> -c=<c>]
.
Note that the options are defined as required = true
; this means required within the group, not required within the command.
Picocli will validate the arguments and throw a MissingParameterException
if not all dependent arguments were specified. For example:
DependentOptionsDemo example = new DependentOptionsDemo();
CommandLine cmd = new CommandLine(example);
try {
cmd.parseArgs("-a=1", "-b=2");
} catch (MissingParameterException ex) {
assert "Error: Missing required argument(s): -c=<c>".equals(ex.getMessage());
}
Option Sections in Usage Help
The example below uses groups to define options sections in the usage help.
When a group has a non-null heading
(or headingKey
), the options in the group are given the specified heading in the usage help message.
The headingKey
attribute can be used to get the heading text from the command's resource bundle.
This works for mutually exclusive or co-occurring groups, but it is also possible to define a group that does no validation but only creates an option section in the usage help.
Annotate a field or method with @ArgGroup(validate = false)
to create a group for display purposes only. For example:
@Command(name = "sectiondemo", description = "Section demo")
public class OptionSectionDemo {
@ArgGroup(validate = false, heading = "This is the first section%n")
Section1 section1;
static class Section1 {
@Option(names = "-a", description = "Option A") int a;
@Option(names = "-b", description = "Option B") int b;
@Option(names = "-c", description = "Option C") int c;
}
@ArgGroup(validate = false, heading = "This is the second section%n")
Section2 section2;
static class Section2 {
@Option(names = "-x", description = "Option X") int x;
@Option(names = "-y", description = "Option Y") int y;
@Option(names = "-z", description = "Option X") int z;
}
public static void main(String[] args) {
new CommandLine(new OptionSectionDemo()).usage(System.out);
}
}
This prints the following usage help message:
Usage: sectiondemo [-a=<a>] [-b=<b>] [-c=<c>] [-x=<x>] [-y=<y>] [-z=<z>]
Section demo
This is the first section
-a=<a> Option A
-b=<b> Option B
-c=<c> Option C
This is the second section
-x=<x> Option X
-y=<y> Option Y
-z=<z> Option X
Note that the heading text must end with %n
to insert a newline between the heading text and the first option.
This is for consistency with other headings in the usage help, like @Command(headerHeading = "Usage:%n", optionListHeading = "%nOptions:%n")
.
Repeating Composite Argument Groups
The below example shows how groups can be composed of other groups, and how arrays and collections can be used to capture repeating groups (with a multiplicity
greater than one):
@Command(name = "repeating-composite-demo")
public class CompositeGroupDemo {
@ArgGroup(exclusive = false, multiplicity = "1..*")
List<Composite> composites;
static class Composite {
@ArgGroup(exclusive = false, multiplicity = "0..1")
Dependent dependent;
@ArgGroup(exclusive = true, multiplicity = "1")
Exclusive exclusive;
}
static class Dependent {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
static class Exclusive {
@Option(names = "-x", required = true) boolean x;
@Option(names = "-y", required = true) boolean y;
@Option(names = "-z", required = true) boolean z;
}
}
In the above example, the annotated composites
field defines a composite group that must be specified at least once, and may be specified many times (multiplicity = "1..*"
), on the command line.
The synopsis of this command is:
Usage: repeating-composite-demo ([-a=<a> -b=<b> -c=<c>] (-x | -y | -z))...
Each time the group is matched, picocli creates an instance of the Composite
class and adds it to the composites
list.
The Composite
class itself contains two groups: an optional (multiplicity = "0..1"
) group of dependent options that must co-occur, and another group of mutually exclusive options, which is mandatory (multiplicity = "1"
).
The below example illustrates:
CompositeGroupDemo example = new CompositeGroupDemo();
CommandLine cmd = new CommandLine(example);
cmd.parseArgs("-x", "-a=1", "-b=1", "-c=1", "-a=2", "-b=2", "-c=2", "-y");
assert example.composites.size() == 2;
Composite c1 = example.composites.get(0);
assert c1.exclusive.x;
assert c1.dependent.a == 1;
assert c1.dependent.b == 1;
assert c1.dependent.c == 1;
Composite c2 = example.composites.get(1);
assert c2.exclusive.y;
assert c2.dependent.a == 2;
assert c2.dependent.b == 2;
assert c2.dependent.c == 2;
Positional Parameters
When a @Parameters
positional parameter is part of a group, its index
is the index within the group, not within the command.
Variable expansion
From this release, picocli supports variable interpolation (variable expansion) in annotation attributes as well as in text attributes of the programmatic API.
Variable Interpolation Example
@Command(name = "status", description = "This command logs the status for ${PARENT-COMMAND-NAME}.")
class Status {
@Option(names = {"${dirOptionName1:--d}", "${dirOptionName2:---directories}"}, // -d or --directories
description = {"Specify one or more directories, separated by '${sys:path.separator}'.",
"The default is the user home directory (${DEFAULT-VALUE})."},
arity = "${sys:dirOptionArity:-1..*}",
defaultValue = "${sys:user.home}",
split = "${sys:path.separator}")
String[] directories;
}
Predefined Variables
See the user manual for the list of predefined variables.
Custom Variables
In addition, you can define your own variables. Currently the following syntaxes are supported:
${sys:key}
: system property lookup, replaced by the value ofSystem.getProperty("key")
${env:key}
: environment variable lookup, replaced by the value ofSystem.getEnv("key")
${bundle:key}
: look up the value ofkey
in the resource bundle of the command${key}
: search all of the above, first system properties, then environment variables, and finally the resource bundle of the command
Default Values for Custom Variables
You can specify a default value to use when no value is found for a custom variable. The syntax for specifying a default is ${a:-b}
, where a
is the variable name and b
is the default value to use if a
is not found.
Explicit JPMS module
The main picocli-4.0.0.jar
is a JPMS module named info.picocli
.
Starting from picocli 4.0, this jar will be an explicit module instead of an automatic module, so the jlink
tool can be used to provide a trimmed binary image that has only the required modules.
Typically, a modular jar includes the module-info.class
file in its root directory. This causes problems for some older tools, which incorrectly process the module descriptor as if it were a normal Java class. To provide the best backward compatibility, the main picocli artifact is a modular multi-release jar with the module-info.class
file located in META-INF/versions/9
.
Separate picocli-groovy
module
Also, from this release the main picocli-4.x
artifact no longer contains the picocli.groovy
classes: these have been split off into a separate picocli-groovy-4.x
artifact. This was necessary to make the main picocli-4.x.jar
an explicit JPMS module.
Negatable options
From picocli 4.0, options can be negatable
.
class App {
@Option(names = "--verbose", negatable = true) boolean verbose;
@Option(names = "-XX:+PrintGCDetails", negatable = true) boolean printGCDetails;
@Option(names = "-XX:-UseG1GC", negatable = true) boolean useG1GC = true;
}
When an option is negatable, picocli will recognize negative aliases of the option on the command line.
For *nix-style long options, aliases have the prefix 'no-' to the given names.
For Java JVM-style options, the :+
is turned into :-
and vice versa. (This can be changed by customizing the INegatableOptionTransformer
.)
If the negated form of the option is found, for example --no-verbose
, the value is set to the provided default. Otherwise, with a regular call, for example --verbose
, it is set to the opposite of the default.
Fallback value for options
This release introduces a new attribute on the Option
annotation: fallbackValue
for options with optional parameter: assign this value when the option was specified on the command line without parameter.
This is different from the defaultValue
, which is assigned if the option is not specified at all on the command line.
Using a fallbackValue
allows applications to distinguish between cases where
- the option was not specified on the command line (default value assigned)
- the option was specified without parameter on the command line (fallback value assigned)
- the option was specified with parameter on the command line (command line argument value assigned)
This is useful to define options that can function as a boolean "switch" and optionally allow users to provide a (strongly typed) extra parameter value.
The option description may contain the ${FALLBACK-VALUE}
variable which will be replaced with the actual fallback value when the usage help is shown.
Custom parameter processing
Options or positional parameters can be assigned a IParameterConsumer
that implements custom logic to process the parameters for this option or this position. When an option or positional parameter with a custom IParameterConsumer
is matched on the command line, picocli's internal parser is temporarily suspended, and the custom parameter consumer becomes responsible for consuming and processing as many command line arguments as needed.
This can be useful when passing options through to another command.
For example, the unix find
command has a -exec
option to execute some action for each file found. Any arguments following the -exec
option until a ;
or +
argument are not options for the find
command itself, but are interpreted as a separate command and its options.
The example below demonstrates how to implement find -exec
using this API:
@Command(name = "find")
class Find {
@Option(names = "-exec", parameterConsumer = ExecParameterConsumer.class)
List<String> list = new ArrayList<String>();
}
class ExecParameterConsumer implements IParameterConsumer {
public void consumeParameters(Stack<String> args, ArgSpec argSpec, CommandSpec commandSpec) {
List<String> list = argSpec.getValue();
while (!args.isEmpty()) {
String arg = args.pop();
list.add(arg);
// `find -exec` semantics: stop processing after a ';' or '+' argument
if (";".equals(arg) || "+".equals(arg)) {
break;
}
}
}
}
Improved parsing of quoted parameters
Also, from this release, support for quoted parameter values has been improved. Quoted parameter values can now contain nested quoted substrings to give end users fine-grained control over how values are split. See the user manual for details.
Auto-detect terminal width for usage help
From this release, commands defined with @Command(usageHelpAutoWidth = true)
will try to adjust the usage message help layout to the terminal width.
There is also programmatic API to control this via the CommandLine::setUsageHelpAutoWidth
and UsageMessageSpec::autoWidth
methods.
End users may enable this by setting system property picocli.usage.width
to AUTO
, and may disable this by setting this system property to a numeric value.
This feature requires Java 7.
Improved support for Chinese, Japanese and Korean usage help
Picocli will align the usage help message to fit within some user-defined width (80 columns by default).
A number of characters in Chinese, Japanese and Korean (CJK) are wider than others.
If those characters are treated to have the same width as other characters, the usage help message may extend past the right margin.
From this release, picocli will use 2 columns for these wide characters when calculating where to put line breaks, resulting in better usage help message text.
This can be switched off with CommandLine.setAdjustLineBreaksForWideCJKCharacters(false)
.
Fixed issues
4.0.0-GA
- [#752][#658][#496] Add
picocli-spring-boot-starter
module including aPicocliSpringFactory
and auto-configuration. Thanks to Thibaud Lepretre for the pull request. - [#736] API: Allow removal of
ArgSpec
fromCommandSpec
. Thanks to AkosCz for the feature request. - [#756] API: Make synopsis indent for multi-line synopsis configurable (related to #739).
- [#761] API: Add
ParseResult.matchedArgs()
method to return all matched arguments in order; changeParseResult.matchedOptions()
andParseResult.matchedPositionals()
to return the full list of matched options and positional parameters, including duplicates if the option or positional parameter was matched multiple times. Thanks to Michael D. Adams for the feature request. - [#760] API: Deprecate
CommandLine.setSplitQuotedStrings
: the vast majority of applications want tosplit
while respecting quotes. - [#754] API/Enhancement: Allow boolean options to get value from fallback instead of defaultProvider. Thanks to Michael D. Adams for the feature request.
- [#696][#741] Enhancement: Automatically split lines in TextTable. Thanks to Sualeh Fatehi for the pull request.
- [#744] Enhancement: Composite Argument Groups: more informative error messages. Thanks to Andreas Deininger for raising this.
- [#745] Enhancement: Picocli should disallow
split
regex for single-value type options. Thanks to Andreas Deininger for raising this. - [#748] Enhancement: Provide API to use a custom Layout in usage help message: ensure
Help.createDefaultLayout()
is used internally so that subclasses overriding this method can control the Layout that is used. - [#595] Enhancement: Support for quoted arguments containing nested quoted substrings, allowing end-users to control how values are split in parts when a
split
regex is defined. - [#739] Bugfix: infinite loop or exception when command name plus synopsis heading length equals or exceeds usage help message width. Thanks to Arturo Alonso for raising this.
- [#746] Bugfix: Apply default values to options and positional parameters in argument groups. Thanks to Andreas Deininger for raising this.
- [#742] Bugfix: Default values prevent correct parsing in argument groups. Thanks to Andreas Deininger for raising this.
- [#759] Bugfix: Correct tracing when custom end-of-option delimiter is matched on the command line.
- [#738] Bugfix:
setTrimQuotes
does not trim quotes from option names. Thanks to Judd Gaddie for raising this. - [#758] Bugfix: Duplicate name exception in argument group: better / more concise error message. Thanks to Andreas Deininger for raising this.
- [#751] Build: Make build more portable.
- [#753] Doc: Improve documentation for multi-value fields: mention the
split
attribute. Thanks to feinstein. - [#740] Doc: Update user manual to replace
parse
examples withparseArgs
. - [#713] Doc: Update UML class diagrams for picocli 4.0.
4.0.0-beta-2
- [#280] API:
@Option(fallbackValue = "...")
for options with optional parameter: assign this value when the option was specified on the command line without parameter. Thanks to Paolo Di Tommaso and marinier for the suggestion and in-depth discussion. - [#625] API:
@Command(synopsisSubcommandLabel = "...")
to allow customization of the subcommands part of the synopsis: by default this is[COMMAND]
. Thanks to Sebastian Thomschke and AlcaYezz for the feature request and subsequent discussion. - [#718] API: Add
IParameterConsumer
and@Option(parameterConsumer = Xxx.class)
for passing arguments through to another command, likefind -exec
. Thanks to Reinhard Pointner for the suggestion. - [#721] API: Add public method Text.getCJKAdjustedLength().
- [#634] API: Dynamically detect terminal size. Requires Java 7. Thanks to my colleague Takuya Ishibashi for the suggestion.
- [#737] Deprecate the
parse
method in favor ofparseArgs
. - [#717] Negatable options change: avoid unmappable character
±
for synopsis: it renders as scrambled characters in encoding ASCII and in some terminals. - [#734][#735] Make the picocli jar OSGi friendly. Thanks to Radu Cotescu for the pull request.
- [#733] Improve error message for unmatched arguments. Thanks to my colleague Takuya Ishibashi for raising this.
- [#719] Bugfix: options with variable arity should stop consuming arguments on custom end-of-options delimiter.
- [#720] Bugfix:
@Unmatched
list should be cleared prior to subsequent invocations. - [#723] Bugfix: variables in
defaultValue
were not expanded in usage help option description line forshowDefaultValues = true
. Thanks to Mikaël Barbero for raising this. - [#722] Bugfix: synopsis of deeply nested
@ArgGroup
shows@Options
duplicate on outer level of command. Thanks to Shane Rowatt for raising this. - [#724] Bugfix: Usage message exceeds width.
- [#731] Doc: Add Zero Bugs Commitment to README.
4.0.0-beta-1b
- [#500] Add a generic and extensible picocli annotation processor
- [#699] Add annotation processor that generates
reflect-config.json
during build - [#703] Add annotation processor that generates
resource-config.json
during build - [#704] Add annotation processor that generates
proxy-config.json
during build - [#707] Add example maven/gradle projects that demonstrate using the annotation processor
- [#711] API: Create separate
picocli-groovy
module, makepicocli
an explicit module (a modular multiversion jar) - [#694] API:
negatable
boolean options. Thanks to Michael D. Adams for the feature request. - [#712] Boolean options should not toggle by default, to be consistent with negatable options
- [#709] Fix scrambled characters for the
±
character when running on system with non-UTF8 encoding - [#717] Fix unmappable character for encoding ASCII by setting compiler encoding to UTF8 explicitly. Thanks to Liam Esteban Prince for raising this.
- [#697] Option sort in usage help should ignore option name prefix; long options without short name should be inserted alphabetically, instead of always appear at the top.
- [#695] Fix runtime warnings about illegal reflective access to field
java.io.FilterOutputStream.out
. Thanks to gitfineon for reporting this issue. - [#698] Reduce
reflect-config.json
used by GraalVM native-image generation - [#700] Change default exit codes to
1
for Exceptions in client code,2
for invalid usage. Add links toExitCode
javadoc. - [#715] processor tests should not fail when running in different locale
- [#710] Let annotation processor validate negatable options, usageHelp options
- [#716] Revert
@Inherited
annotation for@Command
. Thanks to Mikusch for raising this.
4.0.0-alpha-3
- [#516] API: Add support for color schemes in the convenience methods and associated classes and interfaces. Thanks to Bob Tiernay for the suggestion.
- [#561] API: Parser configuration for convenience methods.
- [#650] API: Global parser configuration if using Runnable. Thanks to gitfineon for raising this.
- [#424] API: Exit on help, version or invalid arguments. Thanks to Gerard Bosch for raising this.
- [#541] API: Improved exception handling for Runnable/Callable.
- [#680] API: Add annotation API for exitCodeList and exitCodeListHeading.
- [#611] API: Add
CommandLine.addSubcommand
overloaded method without name or alias. Thanks to andrewbleonard for the request. - [#684] API: Make
CommandLine.defaultFactory
method public. - [#675] API: Make
Help.ColorScheme
immutable. This is a breaking API change. - [#673] API: Deprecate
CommandLine.Range
public fields, add accessor methods to use instead. - [#663] How to remove stacktraces on error. Thanks to Nicolas Mingo and jrevault for raising this and subsequent discussion.
- [#672] Need way to send errors back from subcommand. Thanks to Garret Wilson for raising this.
- [#678] Exit Status section in usage help message.
- [#683] Ensure exitCodeList implementation is consistent with other usage message attributes.
- [#575] Codegen: Use mixinStandardHelpOptions in
AutoComplete$App
(add support for the--version
option) - [#645] Codegen: Exclude Jansi Console from generated GraalVM reflection configuration. Thanks to shanetreacy for raising this.
- [#686] Codegen: Add support for
@Command
interfaces (dynamic proxies) in GraalVM native image. - [#669] Codegen: Add support for resource bundles in GraalVM native image.
- [#691] Codegen bugfix:
ReflectionConfigGenerator
should not generate config forpicocli.CommandLine$Model$ObjectScope
. - [#674] JPMS module: move module-info.class to root of jar.
- [#676] Bugfix: non-defined variables in
defaultValue
now correctly resolve tonull
, and options and positional parameters are now correctly consideredrequired
only if their default value isnull
after variable interpolation. Thanks to ifedorenko for raising this. - [#682] Bugfix: incorrect evaluation for multiple occurrences of a variable.
- [#689] NPE in codegen OutputFileMixin.
- [#679] Documentation: Update examples for new execute API. Add examples for exit code control and custom exception handlers.
- [#681] Documentation: Add exit code section to Internationalization example in user manual.
4.0.0-alpha-2
- [#495] Publish picocli as a JPMS module in a new artifact
picocli-core-module
. Thanks to Warkdev for the pull request. - [#21] Count double-width Asian characters as two characters for line-breaking purposes.
- [#526] Add support for variable interpolation in message strings. Thanks to Bob Tiernay for the suggestion.
- [#660] Added
@java.lang.annotation.Inherited
to the@picocli.CommandLine.Command
annotation. Thanks to Devin Smith for the suggestion. - [#661] Bugfix for stack overflow when option in an argument group had a default value. Thanks to Andreas Deininger for reporting this.
- [#656] Bugfix for issue where synopsis for composite argument groups did not expand for n..* (n > 1). Thanks to Arno Tuomainen for finding this issue.
- [#654] Bugfix: argument group heading text was not retrieved from ResourceBundle. Thanks to Andreas Deininger for raising this.
- [#635] Bugfix in argument group validation: did not show an error if some but not all parts of a co-occurring group were specified. Thanks to Philipp Hanslovsky for the pull request.
- [#653] Bugfix: argument group validation should be skipped if help was requested. Thanks to Andreas Deininger for raising this.
- [#655] Bugfix: argument group validation silently accepts missing subgroup with multiplicity=1.
- [#652] Documentation: fixes in user manual. Thanks to Andreas Deininger for the pull request.
- [#651] Documentation: fixes in user manual. Thanks to Andreas Deininger for the pull request.
4.0.0-alpha-1
- [#643] Change
%
to%%
when using${DEFAULT-VALUE}
in option description. Thanks to Steffen Rehberg for the pull request. - [#638] Document fallback descriptionKey for options and parameters in user manual. Thanks to Mikusch for the suggestion.
- [#199] mutually exclusive options
- [#295] options that must co-occur (dependent options)
- [#450] option grouping in the usage help message
- [#358] (also [#635]) repeating composite arguments (this should also cover the use cases presented in #454 and #434 requests for repeatable subcommands)
Deprecations
run
, call
, invoke
, and parseWithHandlers
methods replaced by execute
All variants of the run
, call
, invoke
, and parseWithHandlers
methods are deprecated from this release, in favor of the new execute
method.
Similarly, the following classes and interfaces are deprecated:
IParseResultHandler2
is deprecated in favor of the newIExecutionStrategy
interface.IExceptionHandler2
is deprecated in favor of the newIParameterExceptionHandler
IExecutionExceptionHandler
interfaces.- The
AbstractHandler
andAbstractParseResultHandler
classes are deprecated with no replacement.
CommandLine.setSplitQuotedStrings
deprecated
The CommandLine.setSplitQuotedStrings
(and isSplitQuotedStrings
) methods have been deprecated:
Most applications should not change the default. The rare application that does need to split parameter values without respecting quotes should use ParserSpec.splitQuotedStrings(boolean)
.
parse
deprecated in favor of parseArgs
From this release, the parse
method is deprecated in favor of parseArgs
.
Range public fields
The public fields of the Range
class have been deprecated and public methods min()
, max()
, isVariable()
have been added that should be used instead.
Potential breaking changes
picocli.groovy
classes moved to separate artifact
From this release the main picocli-4.x
artifact no longer contains the picocli.groovy
classes: these have been split off into a separate picocli-groovy-4.x
artifact.
Scripts upgrading to picocli 4.0 must change more than just the version number!
Scripts should use @Grab('info.picocli:picocli-groovy:4.x')
from version 4.0, @Grab('info.picocli:picocli:4.x')
will not work.
Split regex on single-value options is now disallowed
Picocli now throws an InitializationException
when a single-value type option or positional parameter has a split
regex.
Only multi-value options or positional parameters should have a split
regex. The runtime check can be disabled by setting system property picocli.ignore.invalid.split
to any value.
(The annotation processor also checks this at compile time; this check cannot be disabled.)
ColorScheme is now immutable
The Help.ColorScheme
class has been made immutable. Its public fields are no longer public.
A new Help.ColorScheme.Builder
class has been introduced to create ColorScheme
instances.
This is a breaking API change: I could not think of a way to do this without breaking backwards compatibility.
Boolean options do not toggle by default
From this release, when a flag option is specified on the command line picocli will set its value to the opposite of its default value.
Prior to 4.0, the default was to "toggle" boolean flags to the opposite of their current value:
if the previous value was true
it is set to false
, and when the value was false
it is set to true
.
Applications can call CommandLine.setToggleBooleanFlags(true)
to enable toggling.
Note that when toggling is enabled, specifying a flag option twice on the command line will have no effect because they cancel each other out.
ParseResult matchedOptions
now returns full list
ParseResult.matchedOptions()
and ParseResult.matchedPositionals()
now return the full list of matched options and positional parameters, including duplicates if the option or positional parameter was matched multiple times.
Prior to this release, these methods would return a list that did not contain duplicates.
Applications interested in the old behavior should use the new matchedOptionSet()
and matchedPositionalSet()
methods that return a Set
.
Error message for unmatched arguments changed
The error message for unmatched arguments now shows the index in the command line arguments where the unmatched argument was found,
and shows the unmatched value in single quotes. This is useful when the unmatched value is whitespace or an empty String.
For example:
Previously: Unmatched arguments: B, C
New : Unmatched arguments from index 1: 'B', 'C'
This may break tests that rely on the exact error message.
Option order changed
Previously, options that only have a long name (and do not have a short name) were always shown before options with a short name.
From this release, they are inserted in the option list by their first non-prefix letter.
This may break tests that expect a specific help message.
Factory
From version 4.0, picocli delegates all object creation to the factory, including creating Collection
instances to capture multi-value @Option
values. Previously, Collection
objects were instantiated separately without involving the factory.
It is recommended that custom factories should fall back to the default factory. Something like this:
@Override
public <K> K create(Class<K> clazz) throws Exception {
try {
return doCreate(clazz); // custom factory lookup or instantiation
} catch (Exception e) {
return CommandLine.defaultFactory().create(clazz); // fallback if missing
}
}