Skip to content

Commit

Permalink
Updated user manual for #192 default option arity; #196 infer type fr…
Browse files Browse the repository at this point in the history
…om generic type; #197 type attribute may override field type

Closes #192.
Closes #196.
Closes #197.
  • Loading branch information
remkop committed Oct 3, 2017
1 parent 33e1a16 commit 88b97fe
Showing 1 changed file with 75 additions and 27 deletions.
102 changes: 75 additions & 27 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -317,33 +317,53 @@ and all subcommands (and nested sub-subcommands) that were added _before_ the co
Subcommands added later will not have the converter added automatically.
To ensure a custom type converter is available to all subcommands, register the type converter last, after adding subcommands.

=== Arrays, Collections, Maps
=== Abstract Field Types
The field's type can be an interface or an abstract class.
The `type` attribute can be used to control for each field what concrete class the string value should be converted to.
For example:

[source,java]
----
class App {
@Option(names = "--big", type = BigDecimal.class) // concrete Number subclass
Number[] big; // array type with abstract component class
@Option(names = "--small", type = Short.class) // other Number subclass
Number[] small;
@Parameters(type = StringBuilder.class) // StringBuilder implements CharSequence
CharSequence address; // interface type
}
----

IMPORTANT: With array fields picocli uses reflection to discover the array element type, but with collections,
Java type erasure means picocli cannot find out the generic type of the collection.
For non-String collections, use the `type` attribute to specify what type to convert the command line arguments to.
=== Arrays, Collections, Maps
NOTE: Starting from picocli v2.0, the `type` attribute is no longer necessary for `Collection` and `Map` fields:
picocli will infer the collection element type from the generic type.
(The `type` attribute still works as before, it is just optional in most cases.)

==== Arrays and Collections

Multiple parameters can be captured together in a single array or `Collection` field. When using a collection, use the `type` attribute to specify the collection element type. For example:
Multiple parameters can be captured together in a single array or `Collection` field.
The array or collection elements can be any type for which a <<Strongly Typed Everything,converter>> is registered.
For example:

[source,java]
----
import java.util.regex.Pattern;
import java.io.File;
class Convert {
@Option(names = "-patterns"); // no `type` annotation attribute needed
Pattern[] patterns; // for array fields
@Option(names = "-patterns", description = "the regex patterns to use");
Pattern[] patterns;
@Parameters(type = File.class)
@Parameters(description = "the files to convert")
List<File> files;
}
----

[source,java]
----
String[] args = { "-patterns", "a*b", "[a-e][i-u]", "--", "file1.txt", "file2.txt" };
String[] args = { "-patterns", "a*b", "-patterns", "[a-e][i-u]", "file1.txt", "file2.txt" };
Convert convert = CommandLine.populateCommand(new Convert(), args);
// convert.patterns now has two Pattern objects
Expand All @@ -353,9 +373,12 @@ Convert convert = CommandLine.populateCommand(new Convert(), args);
NOTE: If a collection is returned from a type converter, the _contents_ of the collection are added to the field, not the collection itself.

==== Maps
Since 1.0.0, picocli supports `Map` fields similar to Java's system properties `-Dkey=value` or Gradle's project properties `-Pmyprop=myvalue`.
Picocli v1.0 introduced support for `Map` fields similar to Java's system properties `-Dkey=value` or Gradle's project properties `-Pmyprop=myvalue`.

`Map` fields may have any type for their key and value. Use the `type` attribute to specify the both the _key type_ and the _value type_. For example:
`Map` fields may have any type for their key and value
as long as a <<Strongly Typed Everything,converter>> is registered for both the key and the value type.
Key and value types are inferred from the map's generic type parameters.
For example:

[source,java]
----
Expand All @@ -364,10 +387,10 @@ import java.net.Proxy.Type;
import java.util.concurrent.TimeUnit;
class MapDemo {
@Option(names = {"-p", "--proxyHost"}, type = {Proxy.Type.class, InetAddress.class});
@Option(names = {"-p", "--proxyHost"});
Map<Proxy.Type, InetAddress> proxies;
@Option(names = {"-u", "--timeUnit"}, type = {TimeUnit.class, Long.class});
@Option(names = {"-u", "--timeUnit"});
Map<TimeUnit, Long> timeout;
}
----
Expand All @@ -381,15 +404,47 @@ Map options may be specified multiple times with different key-value pairs. (See

NOTE: On the command line, the key and the value must be separated by a `=` character.

==== Maps and Collections with Abstract Elements
For raw maps and collections, or when using generics with unbounded wildcards like `Map<?, ?>`, or when the type parameters are themselves abstract classes like `List<CharSequence>` or `Map<? extends Number, ? super Number>`, there is not enough information to convert to a stronger type. By default, the raw String values are added as is to such collections.

The `type` attribute can be specified to convert to a stronger type than String. For example:
[source,java]
----
class TypeDemo {
@Option(names = "-x"); // not enough information to convert
Map<?, ?> weaklyTyped; // String keys and values are added as is
@Option(names = "-y", type = {Short.class, BigDecimal.class});
Map<? extends Number, ? super Number> stronglyTyped;
@Option(names = "-s", type = CharBuffer.class);
List<CharSequence> text;
}
----


== Multiple Values
Arity is the number of parameters that will be consumed by an option.

=== Default Arity
The default arity value of an `@Option` or `@Parameters` field depends on its type.

* Boolean fields: the default arity is 0 (consume zero parameters) the field is toggled to its logical negative when the option name is recognized. (You can <<Boolean Parameters,change this>>.)
* Single-valued types like `int`, `String`, `File`: arity is 1 (consume one parameter). Omitting the option parameter results in a ParameterException: "Missing required parameter for field '<field-name>'".
* Multi-valued types like arrays, collections or maps: consume from zero up to all available parameters (until encountering another option or <<Subcommands,subcommand>>).
* Single-valued types like `int`, `String`, `File`: arity is 1 (consume one parameter). Omitting the option parameter results in a ParameterException: "Missing required parameter for option '-option' (<name>)".
* For multi-valued _options_ (arrays, collections or maps), the default arity is 1: consume one parameter per option. Omitting the option parameter results in a ParameterException: "Missing required parameter for option '-option' (<name>)". To add multiple values, specify the option multiple times.
* For multi-valued _positional parameters_ (arrays, collections or maps), the default arity is `0..*`: consume from zero up to all available parameters.

CAUTION: Prior to picocli v2.0, multi-valued options used to greedily consume as many arguments as possible until
encountering another option or subcommand.
If your application relies on this behaviour, you need to explicitly specify an arity of `0..*` when migrating to picocli v2.0.

=== Multiple Occurrences
Users may specify the same option multiple times. For example:
----
-option 111 -option 222 -option 333
----
Each value is appended to the array or collection.


=== Arity

Expand Down Expand Up @@ -436,21 +491,14 @@ Command line arguments like the following are interpreted as three `int` values
Similarly for <<Maps>>:
[source,java]
----
@Option(names = "-fix", split = "\\|", type = {Integer.class, String.class})
Map<Integer,String> message;
@Option(names = "-fix", split = "\\|")
Map<Integer, String> message;
----
With the above option, command line arguments like the following are interpreted as a set of key-value pairs instead of a single string:
----
-fix 8=FIX.4.4|9=69|35=A|49=MBT|56=TargetCompID|34=9|52=20130625-04:05:32.682|98=0|108=30|10=052
----

=== Multiple Occurrences
Users may also specify the same option multiple times. For example:
----
-option 111 -option 222 -option 333
----
Each value is appended to the array or collection.


== Required Arguments
=== Required Options
Expand Down Expand Up @@ -556,7 +604,7 @@ The above defines options `-a` and `-b`, but what should the parser do with inpu
The `-x` argument "looks like" an option but there is no `-x` option defined...

One possibility is to silently accept such values as positional parameters but this is often not desirable.
From version 1.0.0, picocli determines if the unmatched argument "looks like an option"
From version 1.0, picocli determines if the unmatched argument "looks like an option"
by comparing its leading characters to the prefix characters of the known options.

When the unmatched value is similar to the known options, picocli throws an `UnmatchedArgumentException`
Expand Down Expand Up @@ -680,7 +728,7 @@ The markup will be rendered as ANSI escape codes on supported systems.

image:VersionInfoWithColors.png[Screenshot of version information containing markup with Ansi styles and colors]

From 1.0.0, the `version` may contain https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html[format specifiers]:
From picocli v1.0, the `version` may contain https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html[format specifiers]:

[source,java]
----
Expand Down Expand Up @@ -1618,7 +1666,7 @@ Generally, many applications use options for optional values and parameters for
However, picocli lets you make options required if you want to, see <<Required Arguments>>.

== Tracing
From version 1.0.0, picocli supports parser tracing to facilitate troubleshooting.
Picocli v1.0 introduced support for parser tracing to facilitate troubleshooting.

System property `picocli.trace` controls the trace level. Supported levels are `OFF`, `WARN`, `INFO`, and `DEBUG`. The default trace level is `WARN`.

Expand Down

0 comments on commit 88b97fe

Please sign in to comment.