From 88b97fe894ccae7e7d3bbe400e951fd2e149bcd5 Mon Sep 17 00:00:00 2001 From: rpopma Date: Wed, 4 Oct 2017 01:20:25 +0900 Subject: [PATCH] Updated user manual for #192 default option arity; #196 infer type from generic type; #197 type attribute may override field type Closes #192. Closes #196. Closes #197. --- docs/index.adoc | 102 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 27 deletions(-) diff --git a/docs/index.adoc b/docs/index.adoc index 645fdece1..d659df0fd 100644 --- a/docs/index.adoc +++ b/docs/index.adoc @@ -317,15 +317,35 @@ 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 <> is registered. +For example: [source,java] ---- @@ -333,17 +353,17 @@ 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 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 @@ -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 <> 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] ---- @@ -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 proxies; - @Option(names = {"-u", "--timeUnit"}, type = {TimeUnit.class, Long.class}); + @Option(names = {"-u", "--timeUnit"}); Map timeout; } ---- @@ -381,6 +404,25 @@ 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` or `Map`, 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 stronglyTyped; + + @Option(names = "-s", type = CharBuffer.class); + List text; +} +---- + + == Multiple Values Arity is the number of parameters that will be consumed by an option. @@ -388,8 +430,21 @@ Arity is the number of parameters that will be consumed by an option. 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 <>.) -* 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 ''". -* Multi-valued types like arrays, collections or maps: consume from zero up to all available parameters (until encountering another option or <>). +* 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' ()". +* 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' ()". 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 @@ -436,21 +491,14 @@ Command line arguments like the following are interpreted as three `int` values Similarly for <>: [source,java] ---- -@Option(names = "-fix", split = "\\|", type = {Integer.class, String.class}) -Map message; +@Option(names = "-fix", split = "\\|") +Map 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 @@ -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` @@ -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] ---- @@ -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 <>. == 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`.