diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 93e256f7..cad46870 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -45,7 +45,7 @@ The table below lists the differences between the `PicocliBaseScript2` and `Pico ### Key-only map parameters -By default, picocli expects Map options and positional parameters to look like `key=value`, that is, the option parameter or positional parameter is expected to have a key part and a value part, separated by a `=` character. +By default, picocli expects Map options and positional parameters to look like `key=value`, that is, the option parameter or positional parameter is expected to have a key part and a value part, separated by a `=` character. If this is not the case, picocli shows a user-facing error message: `Value for ... should be in KEY=VALUE format but was ...`. From picocli 4.6, applications can specify a `mapFallbackValue` to allow end users to specify only the key part. The specified `mapFallbackValue` is put into the map when end users to specify only a key. The value type can be wrapped in a `java.util.Optional`. For example: @@ -53,21 +53,21 @@ From picocli 4.6, applications can specify a `mapFallbackValue` to allow end use @Option(names = {"-P", "--properties"}, mapFallbackValue = Option.NULL_VALUE) Map> properties; -@Parameters(mapFallbackValue = "1", description = "... ${MAP-FALLBACK-VALUE} ...") -Map studyTime; +@Parameters(mapFallbackValue = "INFO", description = "... ${MAP-FALLBACK-VALUE} ...") +Map, LogLevel> logLevels; ``` This allows input like the following: ``` - --properties=key1 -Pkey2 HOURS + --properties=key1 -Pkey2 -Pkey3=3 org.myorg.MyClass org.myorg.OtherClass=DEBUG ``` The above input would give the following results: ``` -properties = [key1 : Optional.empty, key2 : Optional.empty] -studyTime = [HOURS : 1L] +properties = [key1: Optional.empty, key2: Optional.empty, key3: Optional[3]] +logLevels = [org.myorg.MyClass: INFO, org.myorg.OtherClass: DEBUG] ``` Note that the option description may contain the [`${MAP-FALLBACK-VALUE}` variable](https://picocli.info/#_predefined_variables) which will be replaced with the actual map fallback value when the usage help is shown. @@ -88,7 +88,7 @@ class SystemPropertiesDemo { ``` ### `Optional` -From version 4.6, picocli automatically handles single-value types wrapped in a `java.util.Optional` container when running on Java 8 or higher. +From version 4.6, picocli supports single-value types wrapped in a `java.util.Optional` container when running on Java 8 or higher. If the option or positional parameter was not specified on the command line, picocli assigns the value `Optional.empty()` instead of `null`. For example: diff --git a/docs/index.adoc b/docs/index.adoc index 4ea3fee8..16176616 100644 --- a/docs/index.adoc +++ b/docs/index.adoc @@ -1457,24 +1457,69 @@ Map options may be specified multiple times with different key-value pairs. (See -p HTTP=123.123.123.123 --proxyHost SOCKS=212.212.212.212 -uDAYS=3 -u HOURS=23 -u=MINUTES=59 --timeUnit=SECONDS=13 ---- -If the field is `null`, picocli will instantiate it when the option or positional parameter is matched. -If the type is not a concrete class, picocli will instantiate a `LinkedHashMap` to preserve the input ordering. +If the annotated field is `null`, picocli will instantiate it when the option or positional parameter is matched. +If the `Map` type is not a concrete class, picocli will instantiate a `LinkedHashMap` to preserve the input ordering. NOTE: On the command line, the key and the value must be separated by a `=` character. Map options and positional parameters can be defined with a `split` regular expression to allow end users to specify multiple values in a single parameter. See the <> section for details. +==== Key-only map parameters +By default, picocli expects Map options and positional parameters to look like `key=value`, +that is, the option parameter or positional parameter is expected to have a key part and a value part, separated by a `=` character. +If this is not the case, picocli shows a user-facing error message: `Value for ... should be in KEY=VALUE format but was ...`. + +From picocli 4.6, applications can specify a `mapFallbackValue` to allow end users to specify only the key part. +The specified `mapFallbackValue` is put into the map when end users to specify only a key. +The value type can be <, wrapped in a `java.util.Optional`>>. +For example: + +.Java +[source,java,role="primary"] +---- +@Option(names = {"-P", "--properties"}, mapFallbackValue = Option.NULL_VALUE) +Map> properties; + +@Parameters(mapFallbackValue = "INFO", description = "... ${MAP-FALLBACK-VALUE} ...") +Map, LogLevel> logLevels; +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Option(names = ["-P", "--properties"], mapFallbackValue = Option.NULL_VALUE) +lateinit var properties: Map> + +@Parameters(mapFallbackValue = "INFO", description = "... ${MAP-FALLBACK-VALUE} ...") +lateinit var logLevels: Map, LogLevel> +---- + +This allows input like the following: + +---- + --properties=key1 -Pkey2 -Pkey3=3 org.myorg.MyClass org.myorg.OtherClass=DEBUG +---- + +The above input would give the following results: +---- +properties = [key1: Optional.empty, key2: Optional.empty, key3: Optional[3]] +logLevels = [org.myorg.MyClass: INFO, org.myorg.OtherClass: DEBUG] +---- + +Note that the option description may contain the <<_predefined_variables,`${MAP-FALLBACK-VALUE}`>> variable which will be replaced with the actual map fallback value when the usage help is shown. + ==== System Properties A common requirement for command line applications is to support the `-Dkey=value` syntax to allow end users to set system properties. The example below uses the `Map` type to define an `@Option`-<> that delegates all key-value pairs to `System::setProperty`. +Note the use of `mapFallbackValue = ""` to allow <>. .Java [source,java,role="primary"] ---- class SystemPropertiesDemo { - @Option(names = "-D") + @Option(names = "-D", mapFallbackValue = "") // allow -Dkey void setProperty(Map props) { props.forEach((k, v) -> System.setProperty(k, v)); } @@ -1485,13 +1530,42 @@ class SystemPropertiesDemo { [source,kotlin,role="secondary"] ---- class SystemPropertiesDemo { - @Option(names = ["-D"]) - fun setProperty(props: Map) { - props.forEach { (k: String, v: String?) -> System.setProperty(k, v) } + @Option(names = ["-D"], mapFallbackValue = "") // allow -Dkey + fun setProperty(props: Map) { + props.forEach { (k: String, v: String) -> System.setProperty(k, v) } } } ---- +=== Optional +From version 4.6, picocli supports single-value types wrapped in a `java.util.Optional` container object when running on Java 8 or higher. +If the option or positional parameter was not specified on the command line, picocli assigns the value `Optional.empty()` instead of `null`. +For example: + +.Java +[source,java,role="primary"] +---- +@Option(names = "-x") +Optional x; + +@Option(names = "-D", mapFallbackValue = Option.NULL_VALUE) +Map> map; +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Option(names = ["-x"]) +lateinit var x: Optional + +@Option(names = ["-D"], mapFallbackValue = Option.NULL_VALUE) +lateinit var map: Map> +---- + +WARNING: Picocli has only limited support for `java.util.Optional` types: +only single-value types, and the values in a `Map` (but not the keys!) can be wrapped in an `Optional` container. +`java.util.Optional` cannot be combined with arrays or other `Collection` classes. + === 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. @@ -9070,6 +9144,7 @@ The following variables are predefined: |Variable | Since | Use in | Meaning |`${DEFAULT-VALUE}`| 3.2 | the description for an option or positional parameter|replaced with the <> for that option or positional parameter |`${FALLBACK-VALUE}`| 4.0 | the description for an option with optional parameter|replaced with the <> for that option or positional parameter +|`${MAP-FALLBACK-VALUE}`| 4.6 | the description for map option or positional parameter that allows key-only parameters|replaced with the <<_key_only_map_parameters,map fallback value>> for that option or positional parameter |`${COMPLETION-CANDIDATES}`| 3.2 | the description for an option or positional parameter| replaced with the completion candidates for that option or positional parameter |`${COMMAND-NAME}`| 4.0 | any section of the usage help message for a command|replaced with the name of the command |`${COMMAND-FULL-NAME}`| 4.0 | any section of the usage help message for a command| replaced with the fully qualified name of the command (that is, preceded by its parent fully qualified name)