cbeust/jcommander — Issue #84: Add delegate (mixin) functionality for creating complex command options
Author: rodionmoiseev
Created: 2011-11-05 11:12:04+00:00
State: open

This is a problem I have bumped into after my software got fairly large and the number of commands and options got bigger.

My software mainly utilizes commands feature. For each of my commands I have a corresponding class that holds all the necessary option fields. As some commands share sets of options, I have been using inheritance to remove duplication of option declaration. But now I am facing more complex combinations of options sharing, and inheritance is no longer enough, because in Java you can only inherit from one class.

I have come-up with a fairly simple solution: delegates (or mixins). The idea is to be able to share options like this:

//For commands that provide help option
class Help {
@Parameter(names="-h")
public boolean help;
}

//For commands that require repository to be specified
class UseRepository{
@Parameter(names="-r", required = true)
public String repo = "/default/repo/location"
}

//Upload command
class UploadCmd{
@ParametersDelegate
public Help helpOpts = new Help();
@ParametersDelegate
public UseRepository repoOpts = new UseRepository();
@Parameter(name="-f")
public boolean force;
}

//usage (nothing new here)
UploadCmd uc = new UploadCmd();
jcommander.addCommand("upload", uc);
jcommander.parse(args);

//check if help is set
if(uc.helpOpts.help){
usage();
}

This allows you to share options in a more flexible way, without using inheritance.

By the way, I have noticed that `JCommander` supports adding any number of objects, so that in theory I should be able to achieve the same effect. However, firstly it didn't appear to work (adding another object overrode the first one), which is probably just a bug, and secondly, it would be not very elegant to do

UploadCmd uc = new UploadCmd();
jcommander.addCommand("upload", uc);
JCommander uc_command = jcommander.getCommands().get("upload");
uc_command.addObject(uc.helpOpts);
uc_command .addObject(uc.repoOpts);

I have already implemented this feature in one of my branches (very simple fix), but it would be nice to hear your opinion on this first.

Regards.