import com.beust.jcommander.Parameter;
public class JCommanderTest {
@Parameter
public List<String> parameters = Lists.newArrayList();
@Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
public Integer verbose = 1;
@Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
public String groups;
@Parameter(names = "-debug", description = "Debug mode")
public boolean debug = false;
}
Recently, I got tired of having to handle command line parsing manually. I took a look at existing frameworks and all the ones that I found (JOpts, JArgs, commons-cli) suffered from the same limitations that I was trying to avoid: they barely cut down on the boiler plate code and they are not very type safe.
So I came up with my own framework, which I called JCommander.
The snippet of code above should give you a pretty good idea of what JCommander looks like, and if you need more information, just head over to the main site. I have already integrated JCommander in TestNG and it has already reduced the code base to handle this simple task significantly.
Let me know what you think.
#1 by Simone Tripodi on July 13, 2010 - 5:27 am
Quote
Hi Cedric,
Looking forward to use it!!!
that simply rocks
#2 by Eugene Kuleshov on July 13, 2010 - 5:38 am
Quote
Kohsuke beat you to that 5 years ago.
http://weblogs.java.net/blog/kohsuke/archive/2005/05/parsing_command.html
#3 by Oscar on July 13, 2010 - 5:44 am
Quote
Nice.
I think the name is a bit misleading ( or my brain preestablished associations are ) I thought it was some sort of FileManager, probably JLineArgs but naaaahh…
This is a very good use of annotations, and I have always hated command line parsing, up to the point where I prefer using system properties: -Ddebug=false but this will definitely will change the way we do command line args processing ( or should I say, the way we won’t do that processing anymore )
You just miss to put in your description “… allowing you to focus on your business, instead of command line processing”
The only question I have, in the sample from TestNG, I don’t see a “main” method, how is the “String[]args” bind to this?
#4 by Cedric on July 13, 2010 - 5:44 am
Quote
Eugene: indeed! I missed that project when I looked around, I was surprised nobody had tried this before.
#5 by Cedric on July 13, 2010 - 5:56 am
Quote
Oscar: this class is just the container that holds the values, look here for the actual use:
http://github.com/cbeust/testng/blob/master/src/main/java/org/testng/TestNG.java#L1080
#6 by Itay Maman on July 13, 2010 - 5:56 am
Quote
Args4j, https://args4j.dev.java.net, should also be mentioned, it is taking a similar approach for solving this problem.
#7 by Patrick on July 13, 2010 - 6:25 am
Quote
JewelCli does something similar; my favorite, stylistically: http://jewelcli.sourceforge.net/usage.html.
#8 by Michael Lee on July 13, 2010 - 6:25 am
Quote
Nice! I did not know that there is arg4j or jcommander. I wrote a wrapper over ‘Jopt’ to do annotation based parsing.
#9 by Wouter Lievens on July 13, 2010 - 8:09 am
Quote
Looks very nice. I’ll give it a try next time I have to do this.
Don’t forget releasing it into a maven repository for easy importing!
#10 by Dominique Gallot on July 13, 2010 - 10:24 am
Quote
Nice use of the annotations !
I quickly check the binary and the source, and I was not able to see the licence term.
Is it Apache Licence like TestNg ?
#11 by Cedric on July 13, 2010 - 10:30 am
Quote
Dominique: Yes, I just updated the pom.xml to specify the Apache 2.0 license.
Pingback: Pedro Newsletter 13.07.2010 « Pragmatic Programmer Issues – pietrowski.info
#12 by Julien Viet on July 13, 2010 - 11:42 am
Quote
I’m using Args4j for annotating Groovy commans for CRaSH (Content Repository Shell). I’ll give a try to jcommander to see how it fits!
#13 by Emmanuel Bourg on July 13, 2010 - 12:52 pm
Quote
Fine but how do you support i18n with this approach?
#14 by Jesse Kuhnert on July 13, 2010 - 6:06 pm
Quote
Looks cool, may try replacing jopt with this as well. Always felt a little dirty looking at all that jopt code I had to write for something meant to simplify. Don’t think it actually amounted to less code, just more flexible ordering/omission of arguments.
More like the Cedric I respect/admire.
#15 by syllant on July 14, 2010 - 9:10 pm
Quote
I also use JewelCli which is very close, but JCommander seems to better handle required/optional options and long/short names. I’ll try it.
#16 by Simone Tripodi on July 15, 2010 - 12:18 am
Quote
Also Reinier Zwitserloot from Project Lombok is maintaining a similar project on github:
http://github.com/rzwitserloot/com.zwitserloot.cmdreader
#17 by rod on July 15, 2010 - 4:21 am
Quote
I think there is a little mistake on the project page (List management description):
@Parameter(names = “-hosts”, description = “Level of verbosity”)
public List hosts = new ArrayList();
should be:
@Parameter(names = “-host”, description = “Level of verbosity”)
public List hosts = new ArrayList();
#18 by Nathan on July 15, 2010 - 12:23 pm
Quote
Password input support would be super-nice. Lots of apps do this, e.g., `mysql -p`: you are prompted to enter a password and it won’t show up in your command history.
#19 by Sam Pullara on July 15, 2010 - 1:50 pm
Quote
I can echo that this is a good idea: http://code.google.com/p/cli-parser/
You can read about it here:
http://www.javarants.com/2005/12/24/java-annotations-make-declarative-programming-easy/
#20 by Nagesh on July 15, 2010 - 1:54 pm
Quote
Sam’s http://code.google.com/p/cli-parser/ does static classes, delimited arrays, parameters as well as methods too.
#21 by syllant on July 15, 2010 - 9:34 pm
Quote
+1 for password input support
#22 by Rafael Naufal on July 16, 2010 - 4:54 am
Quote
Cedric, the attributes annotated with @Parameter need to be public or it is possible to be private?
#23 by Cedric Pronzato on July 21, 2010 - 5:15 am
Quote
Hello,
I think there is a little typo on ‘Lists’ chapter on the project page.
@Parameter(names = “-host”, description = “Level of verbosity”)
public List hosts = new ArrayList();
should be:
@Parameter(names = “-host”, description = “List of hosts to connect to”)
public List hosts = new ArrayList();
#24 by Cedric Pronzato on July 21, 2010 - 5:23 am
Quote
And another comment, I have not yet tested the framework, I am just reading the spec:
It is about list and arity, does an arity of 2 imply 2 mandatory arguments or it can be 0,1,2 ? And then is no arity attribute mean any number of arguments?