You annotate fields with descriptions of your options:
import com.beust.jcommander.Parameter; public class JCommanderExample { @Parameter private List<String> parameters = new ArrayList<String>(); @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity") private Integer verbose = 1; @Parameter(names = "-groups", description = "Comma-separated list of group names to be run") private String groups; @Parameter(names = "-debug", description = "Debug mode") private boolean debug = false; }
JCommanderExample jct = new JCommanderExample(); String[] argv = { "-log", "2", "-groups", "unit" }; new JCommander(jct, argv); Assert.assertEquals(jct.verbose.intValue(), 2);
@Parameter(names = "-debug", description = "Debug mode") private boolean debug = false;
If you want to define a boolean parameter that's true by default, you can declare it as having an arity of 1. Users will then have to specify the value they want explicitly:
@Parameter(names = "-debug", description = "Debug mode", arity = 1) private boolean debug = true;
program -debug true program -debug false
@Parameter(names = "-log", description = "Level of verbosity") private Integer verbose = 1;
java Main -log 3
java Main -log test
@Parameter(names = "-host", description = "The host") private List<String> hosts = new ArrayList<String>();
java Main -host host1 -verbose -host host2
public class ArgsPassword { @Parameter(names = "-password", description = "Connection password", password = true) private String password; }
Value for -password (Connection password):
public class ArgsPassword { @Parameter(names = "-password", description = "Connection password", password = true, echoInput = true) private String password; }
public interface IStringConverter<T> { T convert(String value); }
public class FileConverter implements IStringConverter<File> { @Override public File convert(String value) { return new File(value); } }
@Parameter(names = "-file", converter = FileConverter.class) File file;
public interface IStringConverterFactory { <T> Class<? extends IStringConverter<T>> getConverter(Class<T> forType); }
java App -target example.com:8080
public class HostPort { private String host; private Integer port; }
class HostPortConverter implements IStringConverter<HostPort> { @Override public HostPort convert(String value) { HostPort result = new HostPort(); String[] s = value.split(":"); result.host = s[0]; result.port = Integer.parseInt(s[1]); return result; } }
public class Factory implements IStringConverterFactory { public Class<? extends IStringConverter<?>> getConverter(Class forType) { if (forType.equals(HostPort.class)) return HostPortConverter.class; else return null; }
public class ArgsConverterFactory { @Parameter(names = "-hostport") private HostPort hostPort; }
ArgsConverterFactory a = new ArgsConverterFactory(); JCommander jc = new JCommander(a); jc.addConverterFactory(new Factory()); jc.parse("-hostport", "example.com:8080"); Assert.assertEquals(a.hostPort.host, "example.com"); Assert.assertEquals(a.hostPort.port.intValue(), 8080);
public interface IParameterValidator { /** * Validate the parameter. * * @param name The name of the parameter (e.g. "-host"). * @param value The value of the parameter that we need to validate * * @throws ParameterException Thrown if the value of the parameter is invalid. */ void validate(String name, String value) throws ParameterException; }
public class PositiveInteger implements IParameterValidator { public void validate(String name, String value) throws ParameterException { int n = Integer.parseInt(value); if (n < 0) { throw new ParameterException("Parameter " + name + " should be positive (found " + value +")"); } } }
@Parameter(names = "-age", validateWith = PositiveInteger.class) private Integer age;
@Parameter(description = "Files") private List<String> files = new ArrayList<String>(); @Parameter(names = "-debug", description = "Debugging level") private Integer debug = 1;
java Main -debug file1 file2
public class ArgsPrivate { @Parameter(names = "-verbose") private Integer verbose = 1; public Integer getVerbose() { return verbose; } }
ArgsPrivate args = new ArgsPrivate(); new JCommander(args, "-verbose", "3"); Assert.assertEquals(args.getVerbose().intValue(), 3);
java Main -log:3
java Main -level=42
@Parameters(separators = "=") public class SeparatorEqual { @Parameter(names = "-level") private Integer level = 2; }
public class ArgsMaster { @Parameter(names = "-master") private String master; }
public class ArgsSlave { @Parameter(names = "-slave") private String slave; }
ArgsMaster m = new ArgsMaster(); ArgsSlave s = new ArgsSlave(); String[] argv = { "-master", "master", "-slave", "slave" }; new JCommander(new Object[] { m , s }, argv); Assert.assertEquals(m.master, "master"); Assert.assertEquals(s.slave, "slave");
-verbose file1 file2 file3
java Main @/tmp/parameters
java Main -pairs slave master foo.xml
@Parameter(names = "-pairs", arity = 2, description = "Pairs") private List<String> pairs;
Also, note that only List<String> is allowed for parameters that define an arity. You will have to convert these values yourself if the parameters you need are of type Integer or other (this limitation is due to Java's erasure).
program -foo a1 a2 a3 -bar program -foo a1 -bar
@Parameter(names = "-foo", variableArity = true) public List<String> foo = new ArrayList<String>();
@Parameter(names = { "-d", "--outputDirectory" }, description = "Directory") private String outputDirectory;
java Main -d /tmp java Main --outputDirectory /tmp
@Parameter(names = "-host", required = true) private String host;
private Integer logLevel = 3;
public interface IDefaultProvider { /** * @param optionName The name of the option as specified in the names() attribute * of the @Parameter option (e.g. "-file"). * * @return the default value for this option. */ String getDefaultValueFor(String optionName); }
For example, here is a default provider that will assign a default value of 42 for all your parameters except "-debug":
private static final IDefaultProvider DEFAULT_PROVIDER = new IDefaultProvider() { @Override public String getDefaultValueFor(String optionName) { return "-debug".equals(optionName) ? "false" : "42"; } }; // ... JCommander jc = new JCommander(new Args()); jc.setDefaultProvider(DEFAULT_PROVIDER);
@Parameter(names = "--help", help = true) private boolean help;
git commit --amend -m "Bug fix"
@Parameters(separators = "=", commandDescription = "Record changes to the repository") private class CommandCommit { @Parameter(description = "The list of files to commit") private List<String> files; @Parameter(names = "--amend", description = "Amend") private Boolean amend = false; @Parameter(names = "--author") private String author; }
@Parameters(commandDescription = "Add file contents to the index") public class CommandAdd { @Parameter(description = "File patterns to add to the index") private List<String> patterns; @Parameter(names = "-i") private Boolean interactive = false; }
CommandMain cm = new CommandMain(); JCommander jc = new JCommander(cm); CommandAdd add = new CommandAdd(); jc.addCommand("add", add); CommandCommit commit = new CommandCommit(); jc.addCommand("commit", commit); jc.parse("-v", "commit", "--amend", "--author=cbeust", "A.java", "B.java"); Assert.assertTrue(cm.verbose); Assert.assertEquals(jc.getParsedCommand(), "commit"); Assert.assertTrue(commit.amend); Assert.assertEquals(commit.author, "cbeust"); Assert.assertEquals(commit.files, Arrays.asList("A.java", "B.java"));
Usage: <main class> [options] Options: -debug Debug mode (default: false) -groups Comma-separated list of group names to be run * -log, -verbose Level of verbosity (default: 1) -long A long number (default: 0)
@Parameter(names = "-debug", description = "Debug mode", hidden = true) private boolean debug = false;
First you use the @Parameters annotation at the top of your class to define the name of your message bundle, and then you use the descriptionKey attribute instead of description on all the @Parameters that require translations. This descriptionKey is the key to the string into your message bundle:
@Parameters(resourceBundle = "MessageBundle") private class ArgsI18N2 { @Parameter(names = "-host", description = "Host", descriptionKey = "host") String hostName; }
host: Hôte
When JCommander encounters an object annotated with @ParameterDelegate in one of your objects, it acts as if this object had been added as a description object itself:
class Delegate { @Parameter(names = "-port") private int port; } class MainParams { @Parameter(names = "-v") private boolean verbose; @ParametersDelegate private Delegate delegate = new Delegate(); }
MainParams p = new MainParams(); new JCommander(p).parse("-v", "-port", "1234"); Assert.assertTrue(p.isVerbose); Assert.assertEquals(p.delegate.port, 1234);
@DynamicParameter(names = "-D", description = "Dynamic parameters go here") private Map<String, String> params = new HashMap<String, String>();
import java.io.File import com.beust.jcommander.{JCommander, Parameter} import collection.JavaConversions._ object Main { object Args { // Declared as var because JCommander assigns a new collection declared // as java.util.List because that's what JCommander will replace it with. // It'd be nice if JCommander would just use the provided List so this // could be a val and a Scala LinkedList. @Parameter( names = Array("-f", "--file"), description = "File to load. Can be specified multiple times.") var file: java.util.List[String] = null } def main(args: Array[String]): Unit = { new JCommander(Args, args.toArray: _*) for (filename <- Args.file) { val f = new File(filename) printf("file: %s\n", f.getName) } } }
import com.beust.jcommander.* class Args { @Parameter(names = ["-f", "--file"], description = "File to load. Can be specified multiple times.") List<String> file } new Args().with { new JCommander(it, args) file.each { println "file: ${new File(it).name}" } }
<groupId>com.beust</groupId> <artifactId>jcommander</artifactId> <version>1.30</version>