Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Argument groups: default value is disregarded #746

Closed
deining opened this issue Jun 21, 2019 · 2 comments
Closed

Argument groups: default value is disregarded #746

deining opened this issue Jun 21, 2019 · 2 comments
Milestone

Comments

@deining
Copy link
Contributor

deining commented Jun 21, 2019

I'm running the code below (assertions enabled):

package test;

import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;

public class ArgGroupsTest {

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

    @Command(name = "ArgGroupsTest")
    static class TestCommand implements Runnable {

        @ArgGroup( exclusive = false)
        DataSource datasource;

        static class DataSource {
            @Option(names = "-x", arity = "0..1", defaultValue = "999", fallbackValue = "-88" )
            static int x;
        }

        @Override
        public void run() {
            assert TestCommand.DataSource.x== 999;
            System.out.printf("x = %s%n", TestCommand.DataSource.x);
        }
    }
}

Since x = 0, I'm getting:

Exception in thread "main" java.lang.AssertionError
	at test.ArgGroupsTest$TestCommand.run(ArgGroupsTest.java:28)
        ...

Is this the intended behaviour?

@remkop remkop added this to the 4.0 milestone Jun 21, 2019
remkop added a commit that referenced this issue Jun 22, 2019
@remkop
Copy link
Owner

remkop commented Jun 22, 2019

This looks like a bug. Thank you for raising this!

@remkop
Copy link
Owner

remkop commented Jun 25, 2019

Thanks again for raising this; this clarified the semantics for default values in argument groups quite a bit.

I made some improvements, but it may not behave the way you expect in your example use case (because your example has a static field). Picocli will assign default values in the following cases:

  • before parsing the arguments, any @ArgGroup-annotated field that has been initialized in its declaration will have the @Option and @Parameters fields set to their default value. On the other hand, any @ArgGroup-annotated field that has NOT been initialized in its declaration (so is null) will NOT have their @Option and @Parameters fields set to their defaults (because there is no instance). Even static @Option fields of a @ArgGroup will not be initialized if their enclosing class is not initialized to a non-null value in its declaration.
  • during parsing, when an option or positional parameter of the @ArgGroup is matched on the command line (and the @ArgGroup-annotated field is null), the @ArgGroup-annotated field will be assigned a new instance and the @Option and @Parameters fields in this instance will be initialized to their default values.

To demonstrate:

@Command(name = "ArgGroupsTest")
static class CommandWithDefaultValue {

    @ArgGroup(exclusive = false)
    InitializedGroup initializedGroup = new InitializedGroup();

    @ArgGroup(exclusive = false)
    DeclaredGroup declaredGroup;

    static class InitializedGroup {
        @Option(names = "-staticX", arity = "0..1", defaultValue = "999", fallbackValue = "-88" )
        static int staticX;

        @Option(names = "-instanceX", arity = "0..1", defaultValue = "999", fallbackValue = "-88" )
        int instanceX;
    }

    static class DeclaredGroup {
        @Option(names = "-staticY", arity = "0..1", defaultValue = "999", fallbackValue = "-88" )
        static Integer staticY;

        @Option(names = "-instanceY", arity = "0..1", defaultValue = "999", fallbackValue = "-88" )
        Integer instanceY;
    }
}

@Test
public void test746DefaultValue() {
    //TestUtil.setTraceLevel("DEBUG");
    CommandWithDefaultValue bean = new CommandWithDefaultValue();
    CommandLine cmd = new CommandLine(bean);

    cmd.parseArgs();
    assertEquals(999, bean.initializedGroup.instanceX);
    assertEquals(999, CommandWithDefaultValue.InitializedGroup.staticX);

    assertNull(bean.declaredGroup);
    assertNull(CommandWithDefaultValue.DeclaredGroup.staticY);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants