Skip to content

Commit

Permalink
#152 @command(subcommands) annotation to register subcommands declara…
Browse files Browse the repository at this point in the history
…tively. Closes #152
  • Loading branch information
remkop committed Aug 3, 2017
1 parent a433ace commit a33da38
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 26 deletions.
1 change: 1 addition & 0 deletions RELEASE-NOTES.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

== 0.9.8 - Bugfix and enhancements release for public review. API may change.

* #152 Added support for registering subcommands declaratively with the `@Command(subcommands={...})` annotation. Thanks to https://github.com/nagkumar[nagkumar].
* #146 Show underlying error when type conversion fails
* #147 Toggle boolean flags instead of setting to `true`
* #148 Long string in default value no longer causes infinite loop when printing usage. Thanks to https://github.com/smartboyathome[smartboyathome].
Expand Down
19 changes: 5 additions & 14 deletions src/main/java/picocli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -1247,25 +1247,16 @@ private class Interpreter {
" is missing the mandatory @Command annotation with a 'name' attribute");
}
try {
Constructor<?> constructor = sub.getConstructor();
for (Constructor<?> c : sub.getDeclaredConstructors()) {
if (c.getParameterTypes().length == 0) {
constructor = c;
break;
}
System.out.println(Arrays.toString(c.getParameterTypes()));
}
if (constructor == null) {
throw new IllegalArgumentException("Could not instantiate subcommand class "
+ sub.getName() + ": missing no-arg constructor.");
}
Constructor<?> constructor = sub.getDeclaredConstructor();
constructor.setAccessible(true);
addSubcommand(subCommand.name(), sub.newInstance());
commands.put(subCommand.name(), toCommandLine(constructor.newInstance()));
}
catch (IllegalArgumentException ex) { throw ex; }
catch (NoSuchMethodException ex) { throw new IllegalArgumentException("Cannot instantiate subcommand " +
sub.getName() + ": the class has no constructor", ex); }
catch (Exception ex) {
throw new IllegalStateException("Could not instantiate and add subcommand " +
sub.getName() + " with name '" + subCommand.name() + "'", ex);
sub.getName() + ": " + ex, ex);
}
}
}
Expand Down
28 changes: 16 additions & 12 deletions src/test/java/picocli/CommandLineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2802,30 +2802,34 @@ class App {

assertEquals(expectedOutput, content);
}
@Command(name = "subsub1")
static class SubSub1_testDeclarativelyAddSubcommands {private SubSub1_testDeclarativelyAddSubcommands(){}}

@Command(name = "sub1", subcommands = {SubSub1_testDeclarativelyAddSubcommands.class})
static class Sub1_testDeclarativelyAddSubcommands {public Sub1_testDeclarativelyAddSubcommands(){}}

@Command(subcommands = {Sub1_testDeclarativelyAddSubcommands.class})
static class MainCommand_testDeclarativelyAddSubcommands {}
@Test
public void testDeclarativelyAddSubcommands() {
@Command(name = "subsub1")
class SubSub1 {private SubSub1(){}}

@Command(name = "sub1", subcommands = {SubSub1.class})
class Sub1 {public Sub1(){}}
CommandLine main = new CommandLine(new MainCommand_testDeclarativelyAddSubcommands());
assertEquals(1, main.getSubcommands().size());

@Command(subcommands = {Sub1.class})
class MainCommand {}
CommandLine sub1 = main.getSubcommands().get("sub1");
assertEquals(Sub1_testDeclarativelyAddSubcommands.class, sub1.getCommand().getClass());

CommandLine main = new CommandLine(new MainCommand());
assertEquals(1, main.getSubcommands().size());
assertEquals(Sub1.class, main.getSubcommands().get("sub1").getCommand().getClass());
assertEquals(1, sub1.getSubcommands().size());
CommandLine subsub1 = sub1.getSubcommands().get("subsub1");
assertEquals(SubSub1_testDeclarativelyAddSubcommands.class, subsub1.getCommand().getClass());
}
@Ignore
@Test
public void testDeclarativelyAddSubcommandsFailsWithoutNoArgConstructor() {
@Command(name = "sub1") class ABC {}
@Command(subcommands = {ABC.class}) class MainCommand {}
try {
new CommandLine(new MainCommand());
} catch (IllegalArgumentException ex) {
assertEquals("Could not instantiate subcommand class picocli.CommandLineTest$1ABC: missing no-arg constructor.", ex.getMessage());
assertEquals("Cannot instantiate subcommand picocli.CommandLineTest$1ABC: the class has no constructor", ex.getMessage());
}
}
@Test
Expand Down

0 comments on commit a33da38

Please sign in to comment.