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

Annotation way to represent subcommands #152

Closed
nagkumar opened this issue Jul 28, 2017 · 9 comments
Closed

Annotation way to represent subcommands #152

nagkumar opened this issue Jul 28, 2017 · 9 comments

Comments

@nagkumar
Copy link

nagkumar commented Jul 28, 2017

It would be easy to make commands represented as subcommands through annotation rather than api way

Currently one needs to use addSubcommand api.

@kakawait
Copy link
Contributor

What I did for Picocli Spring boot starter was to keep @Command annotation but using static nested class hierarchy to determine subcommand https://github.com/kakawait/picocli-spring-boot-starter

@remkop
Copy link
Owner

remkop commented Aug 2, 2017

I'm thinking to address this by adding a subcommands attribute to the @Command annotation.

Defining a subcommand hierarchy would look like this:

@Command(subcommands = {
    Capacity.class,
    Park.class,
    Leave.class,
    Status.class,
    Query.class,
    Exit.class })
class MainCommand { }

By calling new CommandLine(new MainCommand()), the declared subcommands are automatically instantiated and added to the CommandLine instance. The result is the same as if subcommands were added programmatically like below:

 new CommandLine(new MainCommand())
    .addSubcommand(new Capacity())
    .addSubcommand(new Park())
    .addSubcommand(new Leave())
    .addSubcommand(new Status())
    .addSubcommand(new Query())
    .addSubcommand(new Exit());

Subcommands referenced in a subcommands attribute must have a @Command annotation with a name attribute, or an exception is thrown from the CommandLine constructor. This name will be used both for parsing and for generating usage help.

Custom type converters registered on an CommandLine instance will apply to all subcommands that were declared on the main command with the subcommands annotation.

To parse the command line, use the CommandLine::parse method (the populateCommand method does not work for subcommands):

// application class
public static void main(String[] args) {
    List<CommandLine> parsedCommands = new CommandLine(new MainCommand()).parse(args);
    // do something

Thoughts?

@nagkumar
Copy link
Author

nagkumar commented Aug 2, 2017

proposed subcommand attribute, to take array of classes is too good.

Not sure why populateCommand should not work for sub commands. It can continue to work the way it is i.e. if developer gives right command and args it would populate it as it is now.

@remkop
Copy link
Owner

remkop commented Aug 2, 2017

I hope that "too good" means you like it. :-)

populateCommand doesn't work well with subcommands because you pass in a domain object and the command line args, and you get back that same domain object.

The problem is that the domain object has no reference to the subcommands. populateCommand is a static method so there's no CommandLine instance that you could query for subcommands. The method doesn't return a list. Also, it returns a domain object, not a CommandLine instance, so again there's no way to figure out what subcommands were specified on the command line. That's why the parse method is more appropriate for subcommands.

@nagkumar
Copy link
Author

nagkumar commented Aug 3, 2017

Truly it is good, as I was thinking just opposite.. i.e. let sub-sub-command have a way to reference its parent, some thing as below

@Command(parent=MainCommand.class)
class Capacity(){
}

@remkop
Copy link
Owner

remkop commented Aug 3, 2017

Ok, glad you like it.

To be honest, I would not know how to implement this the other way around (subcommands knowing about their parent) because it requires the parent to dynamically discover all classes annotated with @Command that they are mentioned in which is not easy.

The above (@Command knowing about its subcommands) I have a clear idea on how it can be implemented and how it could be useful elsewhere (for #121 in particular.)

@nagkumar
Copy link
Author

nagkumar commented Aug 3, 2017

What you proposed can also help in a case, where same sub-command say Capacity can be part of two or more main commands i.e for both

Main1Command() and Main2Command() etc.

@remkop
Copy link
Owner

remkop commented Aug 3, 2017

Yes, that was another consideration.

@nagkumar
Copy link
Author

nagkumar commented Aug 3, 2017

To be honest, I would not know how to implement this the other way around (subcommands knowing about their parent) because it requires the parent to dynamically discover all classes annotated with @command that they are mentioned in which is not easy.

I have not tried, but the solution is here, specially classindex

https://stackoverflow.com/questions/259140/scanning-java-annotations-at-runtime
https://github.com/atteo/classindex

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

3 participants