Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Can be done with <a href="http://jcommander.org/#Complex">JCommander</a>. Every <code>JCommander</code> object is, in its essence, a command with arbitrary number of parameters and/or arbitrary number of nested sub-commands, where the top <code>JCommander</code> object is the <em>root</em> command. Command parameters are always specific to the command they have been declared for and do not interfere with other commands' parameters. The interface for adding a sub-command is not very intuitive but is possible (see the <code>addCommand</code> method()) </p> <p>Here's a proof-of-concept test class:</p> <pre><code>public class Test{ @Test public void nestedSubCommandTest() { GeneralOptions generalOpts = new GeneralOptions(); JCommander jc = new JCommander(generalOpts); Command command = new Command(); JCommander jc_command = addCommand(jc, "command", command); SubCommand1 subcommand1 = new SubCommand1(); JCommander jc_subcommand1 = addCommand(jc_command, "subcommand1", subcommand1); SubCommand2 subcommand2 = new SubCommand2(); JCommander jc_subcommand2 = addCommand(jc_subcommand1, "subcommand2", subcommand2); SubCommand3 subcommand3 = new SubCommand3(); addCommand(jc_subcommand2, "subcommand3", subcommand3); jc.parse("--general-opt", "command", "--opt", "subcommand1", "subcommand2", "--sub-opt2", "subcommand3", "--sub-opt3"); assertTrue(generalOpts.opt);// --general-opt was set assertTrue(command.opt);// command --opt was set assertFalse(subcommand1.opt);// subcommand1 --sub-opt1 was not set assertTrue(subcommand2.opt);// subcommand2 --sub-opt2 was set assertTrue(subcommand3.opt);// subcommand3 --sub-opt3 was set } private static JCommander addCommand(JCommander parentCommand, String commandName, Object commandObject) { parentCommand.addCommand(commandName, commandObject); return parentCommand.getCommands().get(commandName); } public static class GeneralOptions { @Parameter(names = "--general-opt") public boolean opt; } @Parameters public static class Command { @Parameter(names = "--opt") public boolean opt; } @Parameters public static class SubCommand1 { @Parameter(names = "--sub-opt1") public boolean opt; } @Parameters public static class SubCommand2 { @Parameter(names = "--sub-opt2") public boolean opt; } @Parameters public static class SubCommand3 { @Parameter(names = "--sub-opt3") public boolean opt; } } </code></pre> <p><strong>Edit:</strong> How to reuse commands.</p> <p>Solution 1, use inheritance:</p> <pre><code> public class CommonArgs{ @Parameter(names="--common-opt") public boolean isCommonOpt; } @Parameters(description = "my command 1") public class MyCommand1 extends CommonArgs{} @Parameters(description = "my command 2") public class MyCommand2 extends CommonArgs{} </code></pre> <p>I think the usage and behaviour is faily obvious for this one. The one drawback is that you can only extend from one class, which may limit reusability in the future.</p> <p>Solution 2, using composition pattern (see the <a href="http://jcommander.org/#Parameter_delegates">doc here</a>):</p> <pre><code> public class CommonArgs{ @Parameter(names="--common-opt") public boolean isCommonOpt; } @Parameters(description = "my command 1") public class MyCommand1{ @ParametersDelegate public CommonArgs commonArgs = new CommonArgs(); } @Parameters(description = "my command 2") public class MyCommand2{ @ParametersDelegate public CommonArgs commonArgs = new CommonArgs(); } </code></pre> <p>Here, the nested <code>commonArgs</code> classes' parameters will be treated as if they were direct parameters of the command class. You can add as many delegates as you wish, or even nest delegates inside other delegates and so on. To get the value of the delegated option after parsing, just do <code>myCommand1.commonArgs.isCommonOpt</code>, etc.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload