jcommander
jcommander copied to clipboard
Using commands feels a bit awkward at the moment
Using commands isn't as easy as the rest of JCommander.
I have code that looks like this:
CommandLineArgs cl=new CommandLineArgs();
JCommander commander = new JCommander(cl);
Cat cat = new Cat();
commander.addCommand(Cat.NAME, cat);
Tail tail = new Tail();
commander.addCommand(Tail.NAME, tail);
Index index = new Index();
commander.addCommand(Index.NAME, index);
The thing that's bugging me is that I had to define a public static final NAME field in each of my command instead of annotating the class, simply calling
addCommand(command)
The same is the case for using the command:
String command = commander.getParsedCommand();
if(Tail.NAME.equals(command)) {
[...]
}
So there are two places where I still need to juggle with plain strings. Instead, I'd like to have something like
Object commandObject = commander.getParsedCommandObject();
This would be really useful if all registered command objects would implement the same interface, e.g. Runnable. In that case, I could simply cast the returned commandObject and call run() (after checking against null, obviously).
This functionality could even be wrapped into the getParsedCommandObject() method like this:
Runnable commandObject = commander.getParsedCommandObject<Runnable.class>();
I agree that commands are kinda uneasy to use.
I do like the commandName
and commandAliases
in @Parameters
annotation.
I was also trying to get commands to work with enums. Here's some (maybe weird) code: Commands@aeea04.
It'd be nice if I could set @Parameters
(and not just @Parameter
) to each enum element, so I could specify the command description.
The above as it is, results to this:
$ java -jar dist/test.jar --help
Usage: app.Fic [options] [command] [command options]
Options:
-d, --debug display debug messages
Default: false
[...]
Commands:
compress compress and decompress commands
decompress compress and decompress commands
$ java -jar dist/test.jar --help compress
compress and decompress commands
Usage: compress [options]
Options:
* -i, --input the input file
-o, --output the output file
I think using enums for commands is a brilliant idea. Adding annotations to enums does not seem very clean though, but I think it should be easy to extend addCommand(String, Object)
interface to support addCommand(Enum<?>, Object)
and then have a Enum<?> getParsedCommandEnum()
.
You have inspired my for another good idea: How about a addCommand(Object)
method, that would automatically create command name from the class name. So for example:
class Commit{
//parameter definitions here
}
//... main ...
// work out command name from class name => "commit"
jc.addCommand(new Commit());
if("commit".equals(jc.getParsedCommand()){
//go
}
or even
if(Commit.class == jc.getParsedCommandClass()){
//go
}
When using the later, you can avoid declaring extra enums or string constants, and at the same time keep your code refactoring-proof.
@cbeust an old one but some nice thoughts about Command
s in it.
What do you say?
Yes, I agree, lot of good ideas here. I'll go over it and think about how to improve the design of commands, let's keep this open.
In the last project I used JCommander in (not very recently), I used Enum
s to wrap all my command classes. Each Enum
had two fields: a String
to hold the command name and a Class<?>
to hold the corresponding class type of the command. This approach helped me work around the problem @huxi described with an utility like getEnum from Apache Commons.
As @cbeust thinks we had good ideas here, wouldn't it be cool if someone of us would open a PR? 8-)