ant [options] [target [target2 [target3] ...]] Options: -help, -h print this message -lib <path> specifies a path to search for jars and classes -buildfile <file> use given buildfile -file <file> '' -f <file> '' -D<property>=<value> use value for given property -nice number A niceness value for the main thread:Args4j (v2.0.12)
The class below demonstrates how to parse command line options for Ant using Args4j. The
main
method parses some sample arguments and also prints out the usage of the command.
import static org.junit.Assert.*; import java.io.File; import java.util.*; import org.kohsuke.args4j.*; /** * Example of using Args4j for parsing * Ant command line options */ public class AntOptsArgs4j { @Argument(metaVar = "[target [target2 [target3] ...]]", usage = "targets") private List<String> targets = new ArrayList<String>(); @Option(name = "-h", aliases = "-help", usage = "print this message") private boolean help = false; @Option(name = "-lib", metaVar = "<path>", usage = "specifies a path to search for jars and classes") private String lib; @Option(name = "-f", aliases = { "-file", "-buildfile" }, metaVar = "<file>", usage = "use given buildfile") private File buildFile; @Option(name = "-nice", metaVar = "number", usage = "A niceness value for the main thread:\n" + "1 (lowest) to 10 (highest); 5 is the default") private int nice = 5; private Map<String, String> properties = new HashMap<String, String>(); @Option(name = "-D", metaVar = "<property>=<value>", usage = "use value for given property") private void setProperty(final String property) throws CmdLineException { String[] arr = property.split("="); if(arr.length != 2) { throw new CmdLineException("Properties must be specified in the form:"+ "<property>=<value>"); } properties.put(arr[0], arr[1]); } public static void main(String[] args) throws CmdLineException { final String[] argv = { "-D", "key=value", "-f", "build.xml", "-D", "key2=value2", "clean", "install" }; final AntOptsArgs4j options = new AntOptsArgs4j(); final CmdLineParser parser = new CmdLineParser(options); parser.parseArgument(argv); // print usage parser.setUsageWidth(Integer.MAX_VALUE); parser.printUsage(System.err); // check the options have been set correctly assertEquals("build.xml", options.buildFile.getName()); assertEquals(2, options.targets.size()); assertEquals(2, options.properties.size()); } }Running this program prints:
[target [target2 [target3] ...]] : targets -D <property>=<value> : use value for given property -f (-file, -buildfile) <file> : use given buildfile -h (-help) : print this message -lib <path> : specifies a path to search for jars and classes -nice number : A niceness value for the main thread: 1 (lowest) to 10 (highest); 5 is the defaultJCommander (v1.13)
Similarly, here is a class which demonstrates how to parse command line options for Ant using JCommander.
import static org.junit.Assert.*; import java.io.File; import java.util.*; import com.beust.jcommander.*; /** * Example of using JCommander for parsing * Ant command line options */ public class AntOptsJCmdr { @Parameter(description = "targets") private List<String> targets = new ArrayList<String>(); @Parameter(names = { "-help", "-h" }, description = "print this message") private boolean help = false; @Parameter(names = { "-lib" }, description = "specifies a path to search for jars and classes") private String lib; @Parameter(names = { "-buildfile", "-file", "-f" }, description = "use given buildfile") private File buildFile; @Parameter(names = "-nice", description = "A niceness value for the main thread:\n" + "1 (lowest) to 10 (highest); 5 is the default") private int nice = 5; @Parameter(names = { "-D" }, description = "use value for given property") private List<String> properties = new ArrayList<String>(); public static void main(String[] args) { final String[] argv = { "-D", "key=value", "-f", "build.xml", "-D", "key2=value2", "clean", "install" }; final AntOptsJCmdr options = new AntOptsJCmdr(); final JCommander jcmdr = new JCommander(options, argv); // print usage jcmdr.setProgramName("ant"); jcmdr.usage(); // check the options have been set correctly assertEquals("build.xml", options.buildFile.getName()); assertEquals(2, options.targets.size()); assertEquals(2, options.properties.size()); } }Running this program prints:
Usage: ant [options] targets Options: -D use value for given property Default: [key=value, key2=value2] -buildfile, -file, -f use given buildfile -help, -h print this message Default: false -lib specifies a path to search for jars and classes -nice A niceness value for the main thread: 1 (lowest) to 10 (highest); 5 is the default Default: 5Args4j vs JCommander
As you can see from the implementations above, both frameworks are very similar. There are a few differences though:
- JCommander does not have an equivalent to Arg4j's
metaVar
which allows you to display the value that an option might take. For example, if you have an option called "-f" which takes a file, you can setmetaVar="<file>"
and Args4j will display-f <file>
when it prints the usage. This is not possible in JCommander, so it is difficult to see which options take values and which ones don't. - JCommander's
@Parameter
option can only be applied to fields, not methods. This makes it slightly restrictive. In Args4j, you can add the annotation on a "setter" method, which allows you to tweak the value before it is set. In JCommander, you would have to create a custom converter. - In the example above, JCommander was unable to place
-D property=value
options into a map. It was able to save them into a list and then you would have to do some post-processing to convert the elements in the list to key-value pairs in a map. On the other hand, Args4j was able to put the properties straight into the map by applying the annotation on a setter method. - JCommander's usage output is not as pretty as Args4j's. In particular, the description of the "nice" option is not aligned correctly.
JCommander has a built-in way to do the -Dkey=value pattern: @DynamicParameter. It must be on a field of type Map. You can customize the assignment character (defaults to "=").
ReplyDeleteAgree on the lack of metaVar though, that's killing me.
I don't think that `@DynamicParameter` has been released yet because it is not in the latest version (1.20). Good to know that it is coming up though!
ReplyDeleteThanks for the handy comparison!
ReplyDeleteI think #2 (@Parameter on a setter method) has been implemented in JCommander recently: https://groups.google.com/d/topic/jcommander/EchNx4rJFGE/discussion
I've been using args4j for a while, but it's got one shortcoming that annoys me: boolean options are always flags; they can't take a parameter. So you can't have a boolean option which defaults to true, where the user says: 'mycommand --flag=false' to turn the flag off. (You can work around it by using String instead of boolean, but then you have to convert String->boolean in the setter method.)
Correction, Args4j can have boolean options with params, but you have to use a different OptionHandler:
Deletehttp://java.net/jira/browse/ARGS4J-12?focusedCommentId=350653&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_350653
I want to know about jcommander.. so any one can help me in writing a simple program on jcommander that how to parse argument from command line.i want to use two commands like 1-Run & 2- List command.
ReplyDelete