jcommander icon indicating copy to clipboard operation
jcommander copied to clipboard

Variable Arity parameters don't work with setAcceptUnknownOption(true)

Open Kawzeg opened this issue 8 years ago • 7 comments

Using variable arity parameters together with unknown options fails with

ParameterException: Expected a value after parameter -values

JCommander#isOption simply returns true when acceptUnknownOption is true, so DefaultVariableArity#processVariableArity always returns 0, since it thinks the arguments to the variable arity option are options.

This used to work in 1.60, where isOption checked if the option has a prefix.

Example code:

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;

import java.util.List;

public class VarArity {
    @Parameter (names = "-values", variableArity = true)
    private List<String> values;
    @Parameter (names = "-foo")
    private boolean foo;
    @Parameter
    private List<String> files;

    public static void main(String[] args) {
        VarArity app = new VarArity();
        JCommander jCommander = new JCommander(app);
        jCommander.setAcceptUnknownOptions(true);
        jCommander.parse("-values", "one", "two", "-foo", "-bar", "foobar.txt");
    }
}

Kawzeg avatar Jun 28 '17 10:06 Kawzeg

We just hit this when attempting to upgrade from 1.58.

tomdcc avatar Oct 26 '18 02:10 tomdcc

Also, hit this when upgrading from 1.48 to 1.72.

Timunas avatar Jan 15 '19 18:01 Timunas

Confirming on this side as well. Unfortunately in our situation we can't simply disable setAcceptUnknownOptions because we use a polymorphic command line parser.

        JCommander commander = JCommander.newBuilder().addObject(options).build();
        commander.setProgramName(CodegenCLI.class.getSimpleName());
        commander.setAcceptUnknownOptions(true);
        commander.parse(args);
        
        ModelBuilder modelBuilder = new ModelBuilder(options);
        APIModel apiModel = modelBuilder.build();
        AbstractGenerator<?> generator = getGenerator(options.getGeneratorClassName(), apiModel);
        try {
            generator.populateOptions(args);

Where populateOptions is:

    public void populateOptions(String[] commandLineArgs) {
        O options = createOptions();
        if (options != null) {
            commander = JCommander.newBuilder().addObject(options).build();
            commander.parse(commandLineArgs);
        }
        this.options = options;
    }

That is to say, the first pass we have unknown options which are subsequently included based on an input parameter causing a re-evaluation of the options. Nonetheless in the "generic" parser JCommander commander we have some variableArity=true arguments which are left broken.

csirostu avatar Apr 23 '19 06:04 csirostu

Are there plans to fix this?

l0rinc avatar Oct 11 '19 08:10 l0rinc

@cbeust, any plans?

l0rinc avatar Jan 11 '20 16:01 l0rinc

Happy to accept a PR.

cbeust avatar Jan 11 '20 17:01 cbeust

What does it mean to accept unknown options? I don't see anything in the documentation about it.

Edit: Leaving an explanation here in case others see this and didn't know: if accept unknown options is true, then passing an unknown parameter (e.g. "-bar" in the example that started this thread) will simply be ignored. If it is false, then an exception is thrown here

buzzlawless avatar May 11 '20 22:05 buzzlawless