1 2= JCommander 3:author: Cédric Beust 4:email: cedric@beust.com 5:toc: left 6:source-highlighter: prettify 7:sectnums: 8 9++++ 10<div style="float:right"> 11<div style="display:inline-block"> 12 <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top"> 13 <input type="hidden" name="cmd" value="_donations"> 14 <input type="hidden" name="business" value="cedric@beust.com"> 15 <input type="hidden" name="lc" value="US"> 16 <input type="hidden" name="item_name" value="Cedric Beust"> 17 <input type="hidden" name="no_note" value="0"> 18 <input type="hidden" name="currency_code" value="USD"> 19 <input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest"> 20 <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"> 21 <img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1" hidden="" style="display: none !important;"> 22 </form> 23</div> 24</div> 25++++ 26 27 28__"Because life is too short to parse command line parameters"__ 29 30== Overview 31 32JCommander is a very small Java framework that makes it trivial to parse command line parameters. 33You annotate fields with descriptions of your options: 34 35[source,java] 36---- 37import com.beust.jcommander.Parameter; 38 39public class Args { 40 @Parameter 41 private List<String> parameters = new ArrayList<>(); 42 43 @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity") 44 private Integer verbose = 1; 45 46 @Parameter(names = "-groups", description = "Comma-separated list of group names to be run") 47 private String groups; 48 49 @Parameter(names = "-debug", description = "Debug mode") 50 private boolean debug = false; 51} 52---- 53 54and then you simply ask JCommander to parse: 55 56[source,java] 57---- 58Args args = new Args(); 59String[] argv = { "-log", "2", "-groups", "unit" }; 60JCommander.newBuilder() 61 .addObject(args) 62 .build() 63 .parse(argv); 64 65Assert.assertEquals(jct.verbose.intValue(), 2); 66---- 67 68Here is another example: 69 70[source,java] 71---- 72class Main { 73 @Parameter(names={"--length", "-l"}) 74 int length; 75 @Parameter(names={"--pattern", "-p"}) 76 int pattern; 77 78 public static void main(String ... argv) { 79 Main main = new Main(); 80 JCommander.newBuilder() 81 .addObject(main) 82 .build() 83 .parse(argv); 84 main.run(); 85 } 86 87 public void run() { 88 System.out.printf("%d %d", length, pattern); 89 } 90} 91---- 92 93[source,bash] 94---- 95$ java Main -l 512 --pattern 2 96512 2 97---- 98 99 100== Types of options 101 102The fields representing your parameters can be of any type. Basic types (`Integer`, `Boolean`, etc...) are supported by default and you can write type converters to support any other type (`File`, etc...). 103 104=== Boolean 105 106When a Parameter annotation is found on a field of type `boolean` or `Boolean`, JCommander interprets it as an option with an arity of 0: 107 108[source,java] 109---- 110@Parameter(names = "-debug", description = "Debug mode") 111private boolean debug = false; 112---- 113 114Such a parameter does not require any additional parameter on the command line and if it's detected during parsing, the corresponding field will be set to true. 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: 115 116[source,java] 117---- 118@Parameter(names = "-debug", description = "Debug mode", arity = 1) 119private boolean debug = true; 120---- 121 122Invoke with either of: 123 124[source,bash] 125---- 126program -debug true 127program -debug false 128---- 129 130When a Parameter annotation is found on a field of type `String`, `Integer`, `int`, `Long` or `long`, JCommander will parse the following parameter and it will attempt to cast it to the right type: 131 132[source,java] 133---- 134@Parameter(names = "-log", description = "Level of verbosity") 135private Integer verbose = 1; 136---- 137 138[source,bash] 139---- 140java Main -log 3 141---- 142 143will cause the field verbose to receive the value 3. However: 144 145[source,bash] 146---- 147$ java Main -log test 148---- 149 150will cause an exception to be thrown. 151 152=== Lists 153 154When a Parameter annotation is found on a field of type `List`, JCommander will interpret it as an option that can occur multiple times: 155 156[source,java] 157---- 158@Parameter(names = "-host", description = "The host") 159private List<String> hosts = new ArrayList<>(); 160---- 161 162will allow you to parse the following command line: 163 164[source,bash] 165---- 166$ java Main -host host1 -verbose -host host2 167---- 168 169When JCommander is done parsing the line above, the field hosts will contain the strings `"host1"` and `"host2"`. 170 171=== Password 172 173If one of your parameters is a password or some other value that you do not wish to appear in your history or in clear, you can declare it of type password and JCommander will then ask you to enter it in the console: 174 175[source,java] 176---- 177public class ArgsPassword { 178 @Parameter(names = "-password", description = "Connection password", password = true) 179 private String password; 180} 181---- 182 183When you run your program, you will get the following prompt: 184 185[source,bash] 186---- 187Value for -password (Connection password): 188---- 189 190You will need to type the value at this point before JCommander resumes. 191 192=== Echo Input 193 194In Java 6, by default, you will not be able to see what you type for passwords entered at the prompt (Java 5 and lower will always show the password). However, you can override this by setting echoInput to `true` (default is `false` and this setting only has an effect when password is `true`): 195 196[source,java] 197---- 198public class ArgsPassword { 199 @Parameter(names = "-password", description = "Connection password", password = true, echoInput = true) 200 private String password; 201} 202---- 203 204== Custom types (converters and splitters) 205 206To bind parameters to custom types or change the way how JCommander splits parameters (default is to split via comma) JCommander provides two 207interfaces `IStringConverter` and `IParameterSplitter`. 208 209[[single-value]] 210=== Custom types - Single value 211 212Use either the `converter=` attribute of the `@Parameter` or implement `IStringConverterFactory`. 213 214==== By annotation 215 216By default, JCommander parses the command line into basic types only (strings, booleans, integers and longs). Very often, your application actually needs more complex types (such as files, host names, lists, etc.). To achieve this, you can write a type converter by implementing the following interface: 217 218[source,java] 219---- 220public interface IStringConverter<T> { 221 T convert(String value); 222} 223---- 224 225For example, here is a converter that turns a string into a File: 226 227[source,java] 228---- 229public class FileConverter implements IStringConverter<File> { 230 @Override 231 public File convert(String value) { 232 return new File(value); 233 } 234} 235---- 236 237Then, all you need to do is declare your field with the correct type and specify the converter as an attribute: 238 239[source,java] 240---- 241@Parameter(names = "-file", converter = FileConverter.class) 242File file; 243---- 244 245JCommander ships with a few common converters (for more info please see the implementations of `IStringConverter`). 246 247===== Note 248 249If a converter is used for a `List` field: 250 251[source,java] 252---- 253@Parameter(names = "-files", converter = FileConverter.class) 254List<File> files; 255---- 256 257And the application is called as follows: 258 259[source,bash] 260---- 261$ java App -files file1,file2,file3 262---- 263 264JCommander will split the string `file1,file2,file3` into `file1`, `file2`, `file3` and feed it one by one to the converter. 265 266For an alternative solution to parse a list of values, see <<list-value>>. 267 268==== By factory 269 270If the custom types you use appear multiple times in your application, having to specify the converter in each annotation can become tedious. To address this, you can use an `IStringConverterFactory`: 271 272[source,java] 273---- 274public interface IStringConverterFactory { 275 <T> Class<? extends IStringConverter<T>> getConverter(Class<T> forType); 276} 277---- 278 279For example, suppose you need to parse a string representing a host and a port: 280 281[source,bash] 282---- 283$ java App -target example.com:8080 284---- 285 286You define the holder class : 287 288[source,java] 289---- 290public class HostPort { 291 public HostPort(String host, String port) { 292 this.host = host; 293 this.port = port; 294 } 295 296 final String host; 297 final Integer port; 298} 299---- 300 301and the string converter to create instances of this class: 302 303[source,java] 304---- 305class HostPortConverter implements IStringConverter<HostPort> { 306 @Override 307 public HostPort convert(String value) { 308 String[] s = value.split(":"); 309 return new HostPort(s[0], Integer.parseInt(s[1])); 310 } 311} 312---- 313 314The factory is straightforward: 315 316[source,java] 317---- 318public class Factory implements IStringConverterFactory { 319 public Class<? extends IStringConverter<?>> getConverter(Class forType) { 320 if (forType.equals(HostPort.class)) return HostPortConverter.class; 321 else return null; 322 } 323---- 324 325You can now use the type `HostPort` as a parameter without any converterClass attribute: 326 327[source,java] 328---- 329public class ArgsConverterFactory { 330 @Parameter(names = "-hostport") 331 private HostPort hostPort; 332} 333---- 334 335All you need to do is add the factory to your JCommander object: 336 337[source,java] 338---- 339ArgsConverterFactory a = new ArgsConverterFactory(); 340JCommander jc = JCommander.newBuilder() 341 .addObject(a) 342 .addConverterFactory(new Factory()) 343 .build() 344 .parse("-hostport", "example.com:8080"); 345 346Assert.assertEquals(a.hostPort.host, "example.com"); 347Assert.assertEquals(a.hostPort.port.intValue(), 8080); 348---- 349 350Another advantage of using string converter factories is that your factories can come from a dependency injection framework. 351 352[[list-value]] 353=== Custom types - List value 354 355Use the `listConverter=` attribute of the `@Parameter` annotation and assign a custom `IStringConverter` implementation to convert a `String` into a `List` of values. 356 357==== By annotation 358 359If your application needs a list of complex types, write a list type converter by implementing the same interface as before: 360 361[source,java] 362---- 363public interface IStringConverter<T> { 364 T convert(String value); 365} 366---- 367where `T` is a `List`. 368 369 370For example, here is a list converter that turns a string into a `List<File>`: 371 372[source,java] 373---- 374public class FileListConverter implements IStringConverter<List<File>> { 375 @Override 376 public List<File> convert(String files) { 377 String [] paths = files.split(","); 378 List<File> fileList = new ArrayList<>(); 379 for(String path : paths){ 380 fileList.add(new File(path)); 381 } 382 return fileList; 383 } 384} 385---- 386 387Then, all you need to do is declare your field with the correct type and specify the list converter as an attribute: 388 389[source,java] 390---- 391@Parameter(names = "-files", listConverter = FileListConverter.class) 392List<File> file; 393---- 394 395Now if you call for application as in the following example: 396 397[source,bash] 398---- 399$ java App -files file1,file2,file3 400---- 401 402The parameter `file1,file2,file3` is given to the `listConverter` and will the properly processed. 403 404JCommander ships with a default converter for `String` values. 405 406 407=== Splitting 408 409Use the `splitter=` attribute of the `@Parameter` annotation and assign a custom `IParameterSplitter` implementation to handle how parameters are split in sub-parts. 410 411==== By annotation 412 413By default, JCommander tries to split parameters for `List` field types on commas. 414 415To split parameters on other characters, you can write a custom splitter by implementing the following interface: 416 417[source,java] 418---- 419public interface IParameterSplitter { 420 List<String> split(String value); 421} 422---- 423 424For example, here is a splitter that splits a string on semicolon: 425 426[source,java] 427---- 428public static class SemiColonSplitter implements IParameterSplitter { 429 public List<String> split(String value) { 430 return Arrays.asList(value.split(";")); 431 } 432} 433---- 434 435Then, all you need to do is declare your field with the correct type and specify the splitter as an attribute: 436 437[source,java] 438---- 439@Parameter(names = "-files", converter = FileConverter.class, splitter = SemiColonSplitter.class) 440List<File> files; 441---- 442 443JCommander will split the string `file1;file2;file3` into `file1`, `file2`, `file3` and feed it one by one to the converter. 444 445 446== Parameter validation 447 448Parameter validation can be performed in two different ways: at the individual parameter level or globally. 449 450=== Individual parameter validation 451 452You can ask JCommander to perform early validation on your parameters by providing a class that implements the following interface: 453 454[source,java] 455---- 456public interface IParameterValidator { 457 /** 458 * Validate the parameter. 459 * 460 * @param name The name of the parameter (e.g. "-host"). 461 * @param value The value of the parameter that we need to validate 462 * 463 * @throws ParameterException Thrown if the value of the parameter is invalid. 464 */ 465 void validate(String name, String value) throws ParameterException; 466} 467---- 468 469Here is an example implementation that will make sure that the parameter is a positive integer: 470 471[source,java] 472---- 473public class PositiveInteger implements IParameterValidator { 474 public void validate(String name, String value) 475 throws ParameterException { 476 int n = Integer.parseInt(value); 477 if (n < 0) { 478 throw new ParameterException("Parameter " + name + " should be positive (found " + value +")"); 479 } 480 } 481} 482---- 483 484Specify the name of a class implementing this interface in the `validateWith` attribute of your `@Parameter` annotations: 485 486[source,java] 487---- 488@Parameter(names = "-age", validateWith = PositiveInteger.class) 489private Integer age; 490---- 491 492Attempting to pass a negative integer to this option will cause a ParameterException to be thrown. 493 494Multiple validators may be specified: 495 496[source,java] 497---- 498@Parameter(names = "-count", validateWith = { PositiveInteger.class, CustomOddNumberValidator.class }) 499private Integer value; 500---- 501 502 503=== Global parameter validation 504 505After parsing your parameters with JCommander, you might want to perform additional validation across these parameters, such as making sure that two mutually exclusive parameters are not both specified. Because of all the potential combinations involved in such validation, JCommander does not provide any annotation-based solution to perform this validation because such an approach would necessarily be very limited by the very nature of Java annotations. Instead, you should simply perform this validation in Java on all the arguments that JCommander just parsed. 506 507 508== Main parameter 509 510So far, all the `@Parameter` annotations we have seen had defined an attribute called `names`. You can define one (and at most one) parameter without any such attribute. This parameter needs to be a `List<String>` and it will contain all the parameters that are not options: 511 512[source,java] 513---- 514@Parameter(description = "Files") 515private List<String> files = new ArrayList<>(); 516 517@Parameter(names = "-debug", description = "Debugging level") 518private Integer debug = 1; 519---- 520 521will allow you to parse: 522 523[source,bash] 524---- 525$ java Main -debug file1 file2 526---- 527 528and the field files will receive the strings `"file1"` and `"file2"`. 529 530== Private parameters 531 532Parameters can be private: 533 534[source,java] 535---- 536public class ArgsPrivate { 537 @Parameter(names = "-verbose") 538 private Integer verbose = 1; 539 540 public Integer getVerbose() { 541 return verbose; 542 } 543} 544ArgsPrivate args = new ArgsPrivate(); 545JCommander.newBuilder() 546 .addObject(args) 547 .build() 548 .parse("-verbose", "3"); 549Assert.assertEquals(args.getVerbose().intValue(), 3); 550---- 551 552== Parameter separators 553 554By default, parameters are separated by spaces, but you can change this setting to allow different separators: 555 556[source,bash] 557---- 558$ java Main -log:3 559---- 560 561or 562 563[source,bash] 564---- 565$ java Main -level=42 566---- 567 568You define the separator with the @Parameters annotation: 569 570[source,java] 571---- 572@Parameters(separators = "=") 573public class SeparatorEqual { 574 @Parameter(names = "-level") 575 private Integer level = 2; 576} 577---- 578 579== Multiple descriptions 580 581You can spread the description of your parameters on more than one class. For example, you can define the following two classes: 582 583[source,java] 584---- 585public class ArgsMaster { 586 @Parameter(names = "-master") 587 private String master; 588} 589 590public class ArgsSlave { 591 @Parameter(names = "-slave") 592 private String slave; 593} 594---- 595 596and pass these two objects to JCommander: 597 598[source,java] 599---- 600ArgsMaster m = new ArgsMaster(); 601ArgsSlave s = new ArgsSlave(); 602String[] argv = { "-master", "master", "-slave", "slave" }; 603JCommander.newBuilder() 604 .addObject(new Object[] { m , s }) 605 .build() 606 .parse(argv); 607 608Assert.assertEquals(m.master, "master"); 609Assert.assertEquals(s.slave, "slave"); 610---- 611 612== @ syntax 613 614JCommander supports the @ syntax, which allows you to put all your options into a file and pass this file as parameter: 615 616[[app-listing]] 617[source,bash] 618./tmp/parameters 619---- 620-verbose 621file1 622file2 623file3 624---- 625 626[source,bash] 627---- 628$ java Main @/tmp/parameters 629---- 630 631== Arities (multiple values for parameters) 632 633=== Fixed arities 634 635If some of your parameters require more than one value, such as the following example where two values are expected after -pairs: 636 637[source,bash] 638---- 639$ java Main -pairs slave master foo.xml 640---- 641 642then you need to define your parameter with the arity attribute and make that parameter a `List<String>`: 643 644[source,java] 645---- 646@Parameter(names = "-pairs", arity = 2, description = "Pairs") 647private List<String> pairs; 648---- 649 650You don't need to specify an arity for parameters of type `boolean` or `Boolean` (which have a default arity of 0) and of types `String`, `Integer`, `int`, `Long` and `long` (which have a default arity of 1). 651 652Also, 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). 653 654=== Variable arities 655 656You can specify that a parameter can receive an indefinite number of parameters, up to the next option. For example: 657 658[source,bash] 659---- 660program -foo a1 a2 a3 -bar 661program -foo a1 -bar 662---- 663 664Such a parameter can be parsed in two different ways. 665 666==== With a list 667 668If the number of following parameters is unknown, your parameter must be of type `List<String>` and you 669need to set the boolean `variableArity` to `true`: 670 671[source,java] 672---- 673@Parameter(names = "-foo", variableArity = true) 674public List<String> foo = new ArrayList<>(); 675---- 676 677==== With a class 678 679Alternatively, you can define a class in which the following parameters will be stored, based on their order 680of appearance: 681 682[source,java] 683---- 684static class MvParameters { 685 @SubParameter(order = 0) 686 String from; 687 688 @SubParameter(order = 1) 689 String to; 690} 691 692@Test 693public void arity() { 694 class Parameters { 695 @Parameter(names = {"--mv"}, arity = 2) 696 private MvParameters mvParameters; 697 } 698 699 Parameters args = new Parameters(); 700 JCommander.newBuilder() 701 .addObject(args) 702 .args(new String[]{"--mv", "from", "to"}) 703 .build(); 704 705 Assert.assertNotNull(args.mvParameters); 706 Assert.assertEquals(args.mvParameters.from, "from"); 707 Assert.assertEquals(args.mvParameters.to, "to"); 708} 709---- 710 711== Multiple option names 712 713You can specify more than one option name: 714[source,java] 715---- 716@Parameter(names = { "-d", "--outputDirectory" }, description = "Directory") 717private String outputDirectory; 718---- 719 720will allow both following syntaxes: 721 722[source,bash] 723---- 724$ java Main -d /tmp 725$ java Main --outputDirectory /tmp 726---- 727 728== Other option configurations 729 730You can configure how options are looked up in a few different ways: 731 732- `JCommander#setCaseSensitiveOptions(boolean)`: specify whether options are case sensitive. If you call this method with `false`, then `"-param"` and `"-PARAM"` are considered equal. 733- `JCommander#setAllowAbbreviatedOptions(boolean)`: specify whether users can pass abbreviated options. If you call this method with `true` then users can pass `"-par"` to specify an option called `-param`. JCommander will throw a `ParameterException` if the abbreviated name is ambiguous. 734 735== Required and optional parameters 736 737If some of your parameters are mandatory, you can use the `required` attribute (which default to `false`): 738 739[source,java] 740---- 741@Parameter(names = "-host", required = true) 742private String host; 743---- 744 745If this parameter is not specified, JCommander will throw an exception telling you which options are missing. 746 747== Default values 748 749The most common way to specify a default value for your parameters is to initialize the field at declaration time: 750 751[source,java] 752---- 753private Integer logLevel = 3; 754---- 755 756For more complicated cases, you might want to be able to reuse identical default values across several main classes or be able to specify these default values in a centralized location such as a `.properties` or an XML file. In this case, you can use an `IDefaultProvider`: 757 758[source,java] 759---- 760public interface IDefaultProvider { 761 /** 762 * @param optionName The name of the option as specified in the names() attribute 763 * of the @Parameter option (e.g. "-file"). 764 * 765 * @return the default value for this option. 766 */ 767 String getDefaultValueFor(String optionName); 768} 769---- 770 771By passing an implementation of this interface to your JCommander object, you can now control which default value will be used for your options. Note that the value returned by this method will then be passed to a string converter, if any is applicable, thereby allowing you to specify default values for any types you need. 772 773For example, here is a default provider that will assign a default value of 42 for all your parameters except `"-debug"`: 774 775[source,java] 776---- 777private static final IDefaultProvider DEFAULT_PROVIDER = new IDefaultProvider() { 778 @Override 779 public String getDefaultValueFor(String optionName) { 780 return "-debug".equals(optionName) ? "false" : "42"; 781 } 782}; 783 784// ... 785 786JCommander jc = JCommander.newBuilder() 787 .addObject(new Args()) 788 .defaultProvider(DEFAULT_PROVIDER) 789 .build() 790 791---- 792 793 794== Help parameter 795 796If one of your parameters is used to display some help or usage, you need use the help attribute: 797 798[source,java] 799---- 800@Parameter(names = "--help", help = true) 801private boolean help; 802---- 803 804If you omit this boolean, JCommander will instead issue an error message when it tries to validate your command and it finds that you didn't specify some of the required parameters. 805 806== More complex syntaxes (commands) 807 808Complex tools such as `git` or `svn` understand a whole set of commands, each of which with their own specific syntax: 809 810[source,bash] 811---- 812$ git commit --amend -m "Bug fix" 813---- 814 815Words such as `"commit"` above are called "commands" in JCommander, and you can specify them by creating one arg object per command: 816 817[source,java] 818---- 819@Parameters(separators = "=", commandDescription = "Record changes to the repository") 820private class CommandCommit { 821 822 @Parameter(description = "The list of files to commit") 823 private List<String> files; 824 825 @Parameter(names = "--amend", description = "Amend") 826 private Boolean amend = false; 827 828 @Parameter(names = "--author") 829 private String author; 830} 831 832@Parameters(commandDescription = "Add file contents to the index") 833public class CommandAdd { 834 835 @Parameter(description = "File patterns to add to the index") 836 private List<String> patterns; 837 838 @Parameter(names = "-i") 839 private Boolean interactive = false; 840} 841---- 842 843Then you register these commands with your JCommander object. After the parsing phase, you call `getParsedCommand()` on your JCommander object, and based on the command that is returned, you know which arg object to inspect (you can still use a main arg object if you want to support options before the first command appears on the command line): 844 845[source,java] 846---- 847CommandMain cm = new CommandMain(); 848CommandAdd add = new CommandAdd(); 849CommandCommit commit = new CommandCommit(); 850JCommander jc = JCommander.newBuilder() 851 .addObject(cm) 852 .addCommand("add", add); 853 .addCommand("commit", commit); 854 .build(); 855 856jc.parse("-v", "commit", "--amend", "--author=cbeust", "A.java", "B.java"); 857 858Assert.assertTrue(cm.verbose); 859Assert.assertEquals(jc.getParsedCommand(), "commit"); 860Assert.assertTrue(commit.amend); 861Assert.assertEquals(commit.author, "cbeust"); 862Assert.assertEquals(commit.files, Arrays.asList("A.java", "B.java")); 863---- 864 865== Exception 866 867Whenever JCommander detects an error, it will throw a `ParameterException`. Note that this is a Runtime Exception, since your application is probably not initialized correctly at this point. Also, `ParameterException` contains the 868`JCommander` instance and you can also invoke `usage()` on it if you need to display some help. 869 870== Usage 871 872You can invoke `usage()` on the JCommander instance that you used to parse your command line in order to generate a summary of all the options that your program understands: 873 874[source,bash] 875---- 876Usage: <main class> [options] 877 Options: 878 -debug Debug mode (default: false) 879 -groups Comma-separated list of group names to be run 880 * -log, -verbose Level of verbosity (default: 1) 881 -long A long number (default: 0) 882---- 883 884You can customize the name of your program by calling `setProgramName()` on your JCommander object. Options preceded by an asterisk are required. 885 886You can also specify the order in which each option should be displayed when calling `usage()` by setting the `order` attribute of the `@Parameter` annotation: 887 888[source,java] 889---- 890class Parameters { 891 @Parameter(names = "--importantOption", order = 0) 892 private boolean a; 893 894 @Parameter(names = "--lessImportantOption", order = 3) 895 private boolean b; 896---- 897 898== Hiding parameters 899 900If you don't want certain parameters to appear in the usage, you can mark them as "hidden": 901 902[source,java] 903---- 904@Parameter(names = "-debug", description = "Debug mode", hidden = true) 905private boolean debug = false; 906---- 907 908 909== Internationalization 910 911You can internationalize the descriptions of your parameters. 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: 912 913[source,java] 914---- 915@Parameters(resourceBundle = "MessageBundle") 916private class ArgsI18N2 { 917 @Parameter(names = "-host", description = "Host", descriptionKey = "host") 918 String hostName; 919} 920---- 921 922Your bundle needs to define this key: 923 924[source,bash] 925---- 926host: Hôte 927---- 928 929JCommander will then use the default locale to resolve your descriptions. 930 931== Parameter delegates 932 933If you are writing many different tools in the same project, you will probably find that most of these tools can share configurations. While you can use inheritance with your objects to avoid repeating this code, the restriction to single inheritance of implementation might limit your flexibility. To address this problem, JCommander supports parameter delegates. 934 935When 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: 936 937[source,java] 938---- 939class Delegate { 940 @Parameter(names = "-port") 941 private int port; 942} 943 944class MainParams { 945 @Parameter(names = "-v") 946 private boolean verbose; 947 948 @ParametersDelegate 949 private Delegate delegate = new Delegate(); 950} 951---- 952 953The example above specifies a delegate parameter Delegate which is then referenced in MainParams. You only need to add a `MainParams` object to your 954JCommander configuration in order to use the delegate: 955 956[source,java] 957---- 958MainParams p = new MainParams(); 959JCommander.newBuilder().addObject(p).build() 960 .parse("-v", "-port", "1234"); 961Assert.assertTrue(p.isVerbose); 962Assert.assertEquals(p.delegate.port, 1234); 963---- 964 965== Dynamic parameters 966 967JCommander allows you to specify parameters that are not known at compile time, such as "-Da=b -Dc=d". Such parameters are specified with the `@DynamicParameter` annotation and must be of type `Map<String, String>`. Dynamic parameters are allowed to appear multiple times on the command line: 968 969[source,java] 970---- 971@DynamicParameter(names = "-D", description = "Dynamic parameters go here") 972private Map<String, String> params = new HashMap<>(); 973---- 974 975You can specify a different assignment string than = by using the attribute assignment. 976 977== JCommander in other languages 978 979=== Kotlin 980 981[source,kotlin] 982---- 983class Args { 984 @Parameter 985 var targets: List<String> = arrayListOf() 986 987 @Parameter(names = arrayOf("-bf", "--buildFile"), description = "The build file") 988 var buildFile: String? = null 989 990 @Parameter(names = arrayOf("--checkVersions"), 991 description = "Check if there are any newer versions of the dependencies") 992 var checkVersions = false 993} 994---- 995 996=== Groovy 997 998Courtesy of Paul King: 999 1000[source,groovy] 1001---- 1002import com.beust.jcommander.* 1003 1004class Args { 1005 @Parameter(names = ["-f", "--file"], description = "File to load. Can be specified multiple times.") 1006 List<String> file 1007} 1008 1009new Args().with { 1010 JCommander.newBuilder().addObject(it).build().parse(argv) 1011 file.each { println "file: ${new File(it).name}" } 1012} 1013---- 1014 1015== More examples 1016 1017Here are the description files for a few projects that use JCommander: 1018 1019- https://github.com/cbeust/testng/blob/master/src/main/java/org/testng/CommandLineArgs.java[TestNG] 1020- https://github.com/cbeust/kobalt/blob/master/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt[Kobalt] 1021 1022== Mailing list 1023 1024Join the http://groups.google.com/group/jcommander[JCommander Google group] if you are interested in discussions about JCommander. 1025 1026== Javadocs 1027 1028The Javadocs for JCommander can be found http://jcommander.org/apidocs/[here]. 1029 1030== License 1031 1032JCommander is released under the https://github.com/cbeust/jcommander/blob/master/license.txt[Apache 2.0 license]. 1033 1034== Download 1035 1036You can download JCommander from the following locations: 1037 1038- http://github.com/cbeust/jcommander[Source on github] 1039- Kobalt 1040 1041[source,groovy] 1042---- 1043compile("com.beust:jcommander:1.71") 1044---- 1045 1046- Gradle 1047 1048[source,groovy] 1049---- 1050compile "com.beust:jcommander:1.71" 1051---- 1052 1053- Maven: 1054 1055[source,xml] 1056---- 1057<dependency> 1058 <groupId>com.beust</groupId> 1059 <artifactId>jcommander</artifactId> 1060 <version>1.71</version> 1061</dependency> 1062---- 1063 1064 1065 1066