picocli icon indicating copy to clipboard operation
picocli copied to clipboard

Add support for multi-value defaultValue and fallbackValue for parameters and options

Open deining opened this issue 5 years ago • 5 comments

Somehow related to #877:

Currently, it is possible to annotate a defaultValue for options and parameters. However, one can specify a string/value only, not multiple values. Fortunately, one can workaround this by using split on the option/positional parameter definition, this solution has some limitations, however.

Code example that illustrates the issue:

public class DefaultValueMultipleOptions {

    public static void main(String... args) {
        CommandLine cmd = new CommandLine(new MyFileCommand());
        cmd.execute(args);
    }
}

@Command( name="myCommand", mixinStandardHelpOptions = true)
class MyFileCommand implements Runnable {

    @Parameters(defaultValue = { "default file 1", "default file 2" }) // does not work (yet)
    // @Parameters(defaultValue = "default file 1,default file 2", split = ",") // this is workaround
    String[] files = { "file 1", "file 2" };

    public void run() {
        for (String file : files)
          System.out.println("File: " + file);
        
        System.out.println(String.format("%s files", files.length));
    }
}

As said, this is a low priority enhacement as we have a workaround here. I just wanted to get the author's opinion on this prior to authoring a PR ;-)

deining avatar Nov 25 '19 09:11 deining

If we do #877 then it makes sense to do this as well.

What I haven’t fully thought through is the edge cases. Basically, what if there are multiple default values specified for a single-value option or positional parameter?

remkop avatar Nov 25 '19 12:11 remkop

What I haven’t fully thought through is the edge cases. Basically, what if there are multiple default values specified for a single-value option or positional parameter?

This reminds me of the discussion we had concerning #745. I would propose to implement the same solution that was eventually chosen for #745:

  • runtime initialization exception from the CommandLine constructor
  • compile-time error by the annotation processor

deining avatar Nov 25 '19 13:11 deining

I considered doing this for 4.7, but having second thoughts (and I may give up on this altogether).

The problem is, that while this will be a backwards compatible change for Java, it will be a breaking change for languages that require different syntax for array type vs single value type annotation members.

Specifically for Groovy, Kotlin and Scala, this would be a breaking change: applications need to change their code in order to compile after this change.

For example:

Before the Change (Current Code)

Before the change, defaultValue = "someValue" and fallbackValue = "someValue" are valid syntax in Groovy, Kotlin and Scala.

// groovy / kotlin
@Option(names = ["--log-level"], defaultValue = "INFO")

// scala
@Option(names = Array("--log-level"), defaultValue = "INFO")

After the Change

After the change, [ and ] or Array( and ) become required around the default value:

// groovy / kotlin
@Option(names = ["--log-level"], defaultValue = ["INFO"]) // '[' and ']' become required around the default value

// scala
@Option(names = Array("--log-level"), defaultValue = Array("INFO")) // 'Array(' and ')' become required

I am not sure if this causes a runtime error. (Haven't tried this yet.)

If existing Kotlin, Groovy and Scala applications (compiled against an older version of picocli that requires single-value default values) would continue to work at runtime (with a newer version of picocli that requires array type default values), then it may be feasible to do this.

remkop avatar Feb 21 '22 01:02 remkop

One idea is to add new API for multi-value defaults and leave the existing API as is for single-value defaults.

Something like this:

Option(defaultValues = {"1", "2"}, fallbackValues = {"3", "4"})

This introduces the possibility of some invalid combinations:

  • use of both defaultValue and defaultValues
  • use of defaultValues annotation on single-value option

Both can be handled by throwing an InitializationException at runtime, compile error from annotation processor.

remkop avatar Feb 21 '22 02:02 remkop

Related: https://github.com/remkop/picocli/issues/1743

remkop avatar Jul 17 '22 00:07 remkop