Skip to content

Options specified at method level is not reset in shell mode (via jline3). #1531

@kaushalkumar

Description

@kaushalkumar

Picocli reuse command object when used in interactive mode. While reusing it clears all the instance variable annotated with @Option/@Paramters, but does not reset the options specified at method level. It looks like Picocli does not invokes method annotated with @option unless the matching option is specified in command line. Due to this, when the command is executed with the option, then instance variable is initialized and next the command is executed without the option, then same value gets visible.

We thought of using default value attribute to get it reset, but unfortunately, in our application, we cannot predefine the default value, thus could not take this approach. Kindly check it.

Example code

package example;

import org.jline.console.SystemRegistry;
import org.jline.console.impl.Builtins;
import org.jline.console.impl.SystemRegistryImpl;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.MaskingCallback;
import org.jline.reader.Parser;
import org.jline.reader.impl.DefaultParser;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.shell.jline3.PicocliCommands;
import picocli.shell.jline3.PicocliCommands.PicocliCommandsFactory;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Supplier;


/**
 * Example.
 */
public class Example {

    /**
     * Top-level command that just prints help.
     */
    @Command(name = "", description = "Example root command.", subcommands = {MyCommand.class})
    static class CliCommands implements Runnable {
        public void run() {
            System.out.println(new CommandLine(this).getUsageMessage());
        }
    }

    /**
     * A command with some options to demonstrate issue.
     */
    @Command(name = "cmd", mixinStandardHelpOptions = true, description = "Example test command.")
    static class MyCommand implements Runnable {
        private List<String> modules;

        @Option(names = "-c", description = "comps", split = ",")
        private List<String> comps;

        public List<String> getModules() {
            return modules;
        }
        @Option(names = "-m", description = "modules", split = ",")
        public void setModules(final List<String> modules) {
            this.modules = modules;
        }
        public void run() {
            System.out.println("Modules = " + modules);
            System.out.println("Comps = " + comps);
        }
    }

    /**
     * Main method.
     * @param args arguments.
     * @throws Exception exception.
     */
    public static void main(final String[] args) throws Exception {
        Supplier<Path> workDir = () -> Paths.get(System.getProperty("user.dir"));
        // set up JLine built-in commands
        Builtins builtins = new Builtins(workDir, null, null);
        // set up picocli commands
        CliCommands commands = new CliCommands();

        PicocliCommandsFactory factory = new PicocliCommandsFactory();

        CommandLine cmd = new CommandLine(commands, factory);
        PicocliCommands picocliCommands = new PicocliCommands(cmd);

        Parser parser = new DefaultParser();
        Terminal terminal = TerminalBuilder.builder().build();
        SystemRegistry systemRegistry = new SystemRegistryImpl(parser, terminal, workDir, null);
        systemRegistry.setCommandRegistries(builtins, picocliCommands);
        LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(systemRegistry.completer())
                .parser(parser).variable(LineReader.LIST_MAX, 50).build();
        builtins.setLineReader(reader);
        factory.setTerminal(terminal);

        String prompt = "prompt> ";
        String rightPrompt = null;

        // start the shell and process input until the user quits with Ctrl-D
        String line;
        while (true) {
            systemRegistry.cleanUp();
            line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
            systemRegistry.execute(line);
        }
    }
}

Execution

prompt> cmd
Modules = null
Comps = null
prompt> cmd -c c1 -m m1
Modules = [m1]
Comps = [c1]
prompt> cmd
Modules = [m1]
Comps = null
prompt> 

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions