失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > JCommander(命令行参数解析工具)

JCommander(命令行参数解析工具)

时间:2022-12-13 21:25:21

相关推荐

JCommander(命令行参数解析工具)

Commander是一个用于解析命令行参数的Java框架,支持解析所有基本的数据类型,也支持将命令行解析成用户自定义的类型,只需要写一个转变函数。

1. JCommander用法

将用来表示参数的fields用@Parameter标识:

[java]view plaincopy importcom.beust.jcommander.Parameter;publicclassJCommanderExample{@ParameterprivateList<String>parameters=newArrayList<String>();@Parameter(names={"-log","-verbose"},description="Levelofverbosity")privateIntegerverbose=1;@Parameter(names="-groups",description="Comma-separatedlistofgroupnamestoberun")privateStringgroups;@Parameter(names="-debug",description="Debugmode")privatebooleandebug=false;}

JCommander就可以解析命令行中的参数了:

[java]view plaincopy JCommanderExamplejct=newJCommanderExample();String[]argv={"-log","2","-groups","unit"};newJCommander(jct,argv);Assert.assertEquals(jct.verbose.intValue(),2);

2. 选项类型

Boolean:

[java]view plaincopy @Parameter(names="-debug",description="Debugmode",arity=1)privatebooleandebug=true;

boolean类型默认arity=0,这样的话不要用户为参数设置value,只要参数中有-debug就被parse成true,没有就parse成false。但是如果加上 arity=1,则需要用户明确指定value:

[java]view plaincopy program-debugtrueprogram-debugfalse

String,Interger,Long:

对这几种类型,JCommander会尝试parse随后的参数,并上溯成参数的类型,如果参数不能成功上溯则会产生exception

[java]view plaincopy @Parameter(names="-log",description="Levelofverbosity")privateIntegerverbose=1;[java]view plaincopy javaMain-log3//gotexceptionforthefollowingonejavaMain-logtext

Lists:

如果类型是List,则这个参数可出现多次

[java]view plaincopy @Parameter(names="-host",description="Thehost")privateList<String>hosts=newArrayList<String>();

下例中fields hosts包含了两个字符串

[java]view plaincopy javaMain-hosthost1-verbose-hosthost2

Password:

指明password为true表明这个field是password,我们不想他出现在命令行上,遇到password的参数,用户会被要求在prompt中输入密码

[java]view plaincopy publicclassArgsPassword{@Parameter(names="-password",description="Connectionpassword",password=true)privateStringpassword;}

Echo Input:

当你想让password显示在prompt中时,需要设置echoInput=true,这个setting只有在password=true时才有效

[java]view plaincopy publicclassArgsPassword{@Parameter(names="-password",description="Connectionpassword",password=true,echoInput=true)privateStringpassword;}

3. 自定义类型

当需要更负责的参数时,比如files,host names,lists等,我们可以写一个转换器(converter)来将参数转换成我们想要的格式或类型。转换器需要实现IStringConverter接口

[java]view plaincopy publicinterfaceIStringConverter<T>{Tconvert(Stringvalue);}

a. 通过annotation实现:

下面的converter将string转换成file

[java]view plaincopy publicclassFileConverterimplementsIStringConverter<File>{@OverridepublicFileconvert(Stringvalue){returnnewFile(value);}}

将参数对应的field定义成下面这样,注意要在annotation里指定converter

[java]view plaincopy @Parameter(names="-file",converter=FileConverter.class)Filefile;

b. 通过工厂 factory 实现:

在每个parameter annotation中都指定converter有点烦,可以通过factory解决这个问题。

比如你要将下面的参数解析成host和portjava App -target :8080

定义一个类来放参数

[java]view plaincopy publicclassHostPort{privateStringhost;privateIntegerport;}

写个converter把参数String转换成HostPort

[java]view plaincopy classHostPortConverterimplementsIStringConverter<HostPort>{@OverridepublicHostPortconvert(Stringvalue){HostPortresult=newHostPort();String[]s=value.split(":");result.host=s[0];result.port=Integer.parseInt(s[1]);returnresult;}}

写一个Factory,作用是返回converter

[java]view plaincopy publicclassFactoryimplementsIStringConverterFactory{publicClass<?extendsIStringConverter<?>>getConverter(ClassforType){if(forType.equals(HostPort.class))returnHostPortConverter.class;elsereturnnull;}

参数类也很简单,参数类型直接用HostPort就好了

[java]view plaincopy publicclassArgsConverterFactory{@Parameter(names="-hostport")privateHostPorthostPort;}

没有看到Factory用在什么地方?是在你的程序创建JCommander时传进去的

[java]view plaincopy ArgsConverterFactorya=newArgsConverterFactory();JCommanderjc=newJCommander(a);jc.addConverterFactory(newFactory());jc.parse("-hostport",":8080");Assert.assertEquals(a.hostPort.host,"");Assert.assertEquals(a.hostPort.port.intValue(),8080);

4. 参数验证

通过提供一个实现了IParameterValidator接口的类,可以让JCommander验证你的参数

[java]view plaincopy publicinterfaceIParameterValidator{/***Validatetheparameter.**@paramnameThenameoftheparameter(e.g."-host").*@paramvalueThevalueoftheparameterthatweneedtovalidate**@throwsParameterExceptionThrownifthevalueoftheparameterisinvalid.*/voidvalidate(Stringname,Stringvalue)throwsParameterException;}

下面这个validator可以验证提供的参数为正整数

[java]view plaincopy publicclassPositiveIntegerimplementsIParameterValidator{publicvoidvalidate(Stringname,Stringvalue)throwsParameterException{intn=Integer.parseInt(value);if(n<0){thrownewParameterException("Parameter"+name+"shouldbepositive(found"+value+")");}}}

在parameter annotation中用validateWith来指定验证器

[java]view plaincopy @Parameter(names="-age",validateWith=PositiveInteger.class)privateIntegerage;

5. 主参数

我们可以定义一个main parameter来放所有参数,这个参数不用指定names,必须为List<String>类型

[java]view plaincopy @Parameter(description="Files")privateList<String>files=newArrayList<String>();@Parameter(names="-debug",description="Debugginglevel")privateIntegerdebug=1;

run下面命令行,files会保存‘file1’和‘file2’

[java]view plaincopy javaMain-debugfile1file2

6. 私有参数

参数可以是private的

[java]view plaincopy publicclassArgsPrivate{@Parameter(names="-verbose")privateIntegerverbose=1;publicIntegergetVerbose(){returnverbose;}}[java]view plaincopy ArgsPrivateargs=newArgsPrivate();newJCommander(args,"-verbose","3");Assert.assertEquals(args.getVerbose().intValue(),3);

7. 参数分隔符

参数默认用空格分隔,但是我们也可以指定自己的分隔符,比如用“:”, “=”等,java Main -log:3

可以在参数类定义中使用@Parameter annotation指定分隔符

[java]view plaincopy @Parameters(separators="=")publicclassSeparatorEqual{@Parameter(names="-level")privateIntegerlevel=2;}

8. 多重描述(多个参数类)

你可以将参数放在不同的参数类中,比如定义以下两个含有不同参数的参数类

[java]view plaincopy publicclassArgsMaster{@Parameter(names="-master")privateStringmaster;}[java]view plaincopy publicclassArgsSlave{@Parameter(names="-slave")privateStringslave;}

使用时将两个类都传入JCommander

[java]view plaincopy ArgsMasterm=newArgsMaster();ArgsSlaves=newArgsSlave();String[]argv={"-master","master","-slave","slave"};newJCommander(newObject[]{m,s},argv);Assert.assertEquals(m.master,"master");Assert.assertEquals(s.slave,"slave");

9. @语法

JCommander支持从文件中获取并解析参数,比如文件/tmp/params中包含了以下内容

[java]view plaincopy -verbosefile1file2file3

在命令行中用@指定文件路径即可

[java]view plaincopy javaMain@/tmp/parameters

10. 参数value数量(Arities)

有时候你想为一个参数设置多个值,这时就要用到arity,比如-pairs需要两个values,则设置arity=2

[java]view plaincopy @Parameter(names="-pairs",arity=2,description="Pairs")privateList<String>pairs;

JCommander就会为pairs接收两个values

[java]view plaincopy javaMain-pairsslavemaster

注意想接收多个value的参数需要设置成List<String>类型,boolean类型默认arity为0,String、Integer、int、Long、long默认arity都为1。

可变参数值数量,设置variableArity=true,你可以指定一个参数接收不定数量的values

[java]view plaincopy @Parameter(names="-foo",variableArity=true)publicList<String>foo=newArrayList<String>();

下面两个例子一个接收2个参数,一个接收3个参数

[java]view plaincopy program-fooa1a2a3-barprogram-fooa1-bar

11. 多重选项名

同一个选项(option)可以有不同别名,比如--recursive,可以有一个缩写-r,可以通过给names设置多个值实现

[java]view plaincopy @Parameter(names={"-d","--outputDirectory"},description="Directory")privateStringoutputDirectory;

下面两种都可以给outputDirectory赋值

[java]view plaincopy </pre><prename="code"class="java">javaMain-d/tmpjavaMain--outputDirectory/tmp

12. 其他选项配置

JCommander#setCaseSensitiveOptions(boolean):选项是否大小写敏感,如果设置成true,则‘-option' 和'-OPTION'是不同的选项

JCommander#setAllowAbbreviatedOptions(boolean):打开选项缩写功能,’-op‘可以表示’-option‘选项,如果选项缩写太模糊不能定位到某个选项,则会throw一个ParameterException

13. 必须和可选选项

@Parameter annotation的required设置为true则表示此选项为必须的,否则为可选(默认为可选)

[java]view plaincopy @Parameter(names="-host",required=true)privateStringhost;

14. 默认值

一般情况下直接给选项赋值就可以了

[java]view plaincopy privateIntegerlogLevel=3;

如果有更复杂的情况,比如对某些选项可以再不同的类里重复使用,或者你想把所有的default value都存在同一个地方比如一个XML文件,这些可以通过实现IDefaultProvider接口达成

[java]view plaincopy publicinterfaceIDefaultProvider{/***@paramoptionNameThenameoftheoptionasspecifiedinthenames()attribute*ofthe@Parameteroption(e.g."-file").**@returnthedefaultvalueforthisoption.*/StringgetDefaultValueFor(StringoptionName);}

实例

[java]view plaincopy //这是个内部类[java]view plaincopy privatestaticfinalIDefaultProviderDEFAULT_PROVIDER=newIDefaultProvider(){@OverridepublicStringgetDefaultValueFor(StringoptionName){return"-debug".equals(optionName)?"false":"42";}};//...JCommanderjc=newJCommander(newArgs());jc.setDefaultProvider(DEFAULT_PROVIDER);//把defaultprovider传入

15. 帮助选项

非常简单

[java]view plaincopy @Parameter(names="--help",help=true)privatebooleanhelp;

16. 更多复杂的命令语法

想git之类的工具,除了git命令本身需要选项,它还包含一些子命令,如git commit,子命令本身也包含一些选项

[java]view plaincopy gitcommit--amend-m"Bugfix"

上面的命令中,commit在JCommander中叫做’commands‘, 我们要为这个子命令单独创建一个类

[java]view plaincopy @Parameters(separators="=",commandDescription="Recordchangestotherepository")privateclassCommandCommit{@Parameter(description="Thelistoffilestocommit")privateList<String>files;@Parameter(names="--amend",description="Amend")privateBooleanamend=false;@Parameter(names="--author")privateStringauthor;}

再为另一个git命令add创建一个类

[java]view plaincopy @Parameters(commandDescription="Addfilecontentstotheindex")publicclassCommandAdd{@Parameter(description="Filepatternstoaddtotheindex")privateList<String>patterns;@Parameter(names="-i")privateBooleaninteractive=false;}

创建好后要在JCommander对象里通过addCommand注册这些命令,当然我们也可以创建一个主要的参数类来接受git的参数

[java]view plaincopy CommandMaincm=newCommandMain();JCommanderjc=newJCommander(cm);CommandAddadd=newCommandAdd();jc.addCommand("add",add);CommandCommitcommit=newCommandCommit();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"));

17. Exception

JCommander发现错误时会抛出ParameterExcpetion,这是一个runtime exception

18. usage

可以再JCommander实例中调用usage()方法获取命令行使用方法

19. 隐藏参数

如果不想某些选项出现在usage里,可以隐藏他们

[java]view plaincopy @Parameter(names="-debug",description="Debugmode",hidden=true)privatebooleandebug=false;

20. 国际化

选项的描述(description)可以国际化,首先在类上使用@Parameter指定消息bundle的名字,然后在选项的@Parameter中使用descriptionKey指定bundle中的key

[java]view plaincopy @Parameters(resourceBundle="MessageBundle")privateclassArgsI18N2{@Parameter(names="-host",description="Host",descriptionKey="host")StringhostName;}

在MessageBundle中,定义host如下

[java]view plaincopy host:主机

21. 参数代理

使用@ParameterDelegate可以在主参数类中引用其他的代理参数类

[java]view plaincopy classDelegate{@Parameter(names="-port")privateintport;}classMainParams{@Parameter(names="-v")privatebooleanverbose;@ParametersDelegateprivateDelegatedelegate=newDelegate();}

使用时只需在JCommander中指定主参数类

[java]view plaincopy MainParamsp=newMainParams();newJCommander(p).parse("-v","-port","1234");Assert.assertTrue(p.isVerbose);Assert.assertEquals(p.delegate.port,1234);

22. 动态参数

JCommander允许接收没有预先定义的选项,比如’-Da=b -Dc=d‘, Da和Dc没有在参数类中定义,这些参数要用@DynamicParameter annotation标记的类型为Map<String, String>的选项接收,动态参数可以重复多次

[java]view plaincopy @DynamicParameter(names="-D",description="Dynamicparametersgohere")privateMap<String,String>params=newHashMap<String,String>();

通过使用assignment属性,可以用其他符号代替’=‘作为赋值符号

/navyhu/article/details/40430267

如果觉得《JCommander(命令行参数解析工具)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。