从Commons CLI迁移到picocli

最初于2002年发布的Apache Commons CLI可能是使用最广泛的Java命令行解析器,但是它的API显示了它的年龄。 寻找具有最少样板代码的现代方法的应用可能对picocli感兴趣。 为什么要花麻烦的钱进行迁移,以及如何将基于Commons CLI的应用程序迁移到picocli? Picocli提供了一种流畅的API,具有强大的输入功能,ANSI颜色的使用帮助,自动补全功能以及许多其他功能。 让我们以Checkstyle为例。

为什么要迁移?

从Commons CLI迁移到picocli是否值得解决? 从一个命令行解析器转到另一个命令行解析器有什么好处? 这不仅仅是重新装修我们应用程序的客厅吗?

最终用户体验

公用CLI

对最终用户有什么好处?

命令行完成 。 基于Picocli的应用程序可以在bash和zsh shell以及基于JLine的交互式shell应用程序中具有命令行完成功能 。

美丽,易读的用法帮助消息。 Commons CLI生成的使用帮助有点简单。 picocli开箱即用地生成帮助,该帮助使用ANSI样式和颜色进行对比以强调命令,选项和参数等重要信息。 使用注释可以轻松自定义帮助消息的布局。 此外,如果您需要其他帮助,还有一个帮助API。 有关一些示例屏幕截图,请参见picocli 自述文件 。

通过@ -files或“ argument files”支持非常大的命令行 。 有时用户需要指定比操作系统或外壳程序支持的命令行更长的命令行。 当picocli遇到以字符@开头的参数时,它将文件的内容扩展到参数列表中。 这使应用程序可以处理任意长度的命令行。

开发人员经验

公用CLI

作为开发人员,对您有什么好处?

通常,picocli应用程序的代码要比Commons CLI的代码少得多。 picocli批注允许应用程序以声明性的方式定义选项和位置参数,所有信息都放在一个位置。 此外,picocli还提供了许多便利,例如类型转换和自动帮助,这些便利照顾了一些机制,因此应用程序可以将更多精力放在业务逻辑上。 本文的其余部分将更详细地说明这一点。

文档 :picocli具有广泛的用户手册和详细的javadoc 。

故障排除 。 Picocli具有内置的跟踪工具,以方便进行故障排除。 最终用户可以使用系统属性picocli.trace来控制跟踪级别。 支持的级别为OFFWARNINFODEBUG 。 默认跟踪级别为WARN

未来扩展

公用CLI

最后,除了立即获得回报之外,从Commons CLI迁移到picocli还可以获得任何未来的好处吗?

Picocli具有许多高级功能 。 您的应用程序可能尚未使用这些功能,但是如果您想将来扩展应用程序,picocli支持嵌套子命令 (以及子子命令到任何深度),可重复使用的mixins ,可轻松与 Dependency Injection容器集成以及一个不断发展的工具框架,可从picocli CommandSpec模型生成源代码,文档和配置文件。

最终,picocli得到了积极维护 ,而Commons CLI似乎在16年内发布了6个版本,几乎处于停滞状态。

迁移示例:CheckStyle

公用CLI

命令行应用程序需要做三件事:

  1. 定义支持的选项
  2. 解析命令行参数
  3. 处理结果

让我们以CheckStyle的com.puppycrawl.tools.checkstyle.Main命令行实用程序为例,比较在Commons CLI和picocli中如何完成此操作。

完整的源代码之前和之后的迁移是在GitHub上。

定义选项和位置参数

使用Commons CLI定义选项

Commons CLI有多种定义选项的方式: Options.addOption ,构造一个new Options(…​)并在此对象,不建议使用的OptionBuilder类和推荐的Option.Builder类上调用方法。

Checkstyle Main类使用Options.addOption方法。 首先为选项名称定义一些常量:

/** Name for the option 's'. */
private static final String OPTION_S_NAME = "s";/** Name for the option 't'. */
private static final String OPTION_T_NAME = "t";/** Name for the option '--tree'. */
private static final String OPTION_TREE_NAME = "tree";... // and more. Checkstyle Main has 26 options in total.

Main.buildOptions方法使用以下常量来构造和返回定义了支持的选项的Commons CLI Options对象:

private static Options buildOptions() {final Options options = new Options();options.addOption(OPTION_C_NAME, true, "Sets the check configuration file to use.");options.addOption(OPTION_O_NAME, true, "Sets the output file. Defaults to stdout");...options.addOption(OPTION_V_NAME, false, "Print product version and exit");options.addOption(OPTION_T_NAME, OPTION_TREE_NAME, false,"Print Abstract Syntax Tree(AST) of the file");...return options;
}

使用Picocli定义选项

在picocli中,您可以使用类似于Commons CLI方法的构建器以编程方式定义支持的选项,也可以使用注释以声明方式定义支持的选项。

对于并非事先知道所有选项的动态应用程序,Picocli的编程API可能会有用。 如果您对编程方法感兴趣,请查看CommandSpecOptionSpecPositionalParamSpec类。 另请参阅Programmatic API 。

在本文中,我们将使用picocli批注。 对于CheckStyle示例,这看起来类似于以下内容:

@Option(names = "-c", description = "Sets the check configuration file to use.")
private File configurationFile;@Option(names = "-o", description = "Sets the output file. Defaults to stdout")
private File outputFile;@Option(names = "-v", versionHelp = true, description = "Print product version and exit")
private boolean versionHelpRequested;@Option(names = {"-t", "--tree"}, description = "Print Abstract Syntax Tree(AST) of the file")
private boolean printAST;

比较方式

陈述式

公用CLI

使用Commons CLI,您可以通过调用具有String值的方法来构建规范。 此类API的一个缺点是,良好的样式会迫使客户端代码定义常量以避免“不可思议的值”,就像Checkstyle Main类尽职尽责。

使用picocli,所有信息都集中在一个地方。 注释仅接受String文字,因此定义和用法会自动放在一起,而无需声明常量。 这样可以使代码更简洁,更少。

强类型

公用CLI

Commons CLI使用布尔标志来表示该选项是否带有参数。

Picocli使您可以直接使用类型。 根据类型,picocli“知道”该选项需要多少个参数: boolean字段没有参数, CollectionMap和array字段可以有零个到任意数量的参数,任何其他类型意味着这些选项只需要一个参数论点。 可以对其进行自定义(请参阅arity ),但是大多数情况下,默认值就足够了。

Picocli鼓励您将enum类型用于带有有限有效值集的选项或位置参数。 picocli不仅会为您验证输入,还可以使用@Option(description = "Valid values: ${COMPLETION-CANDIDATES}")在使用帮助消息中显示所有值 。 枚举还允许命令行补全功能为选项值建议补全候选值。

更少的代码

公用CLI

Picocli 将选项参数String值转换为字段类型。 它不仅可以节省应用程序的工作量,而且还可以对用户输入进行最小程度的验证。 如果转换失败,则会引发ParameterException并显示用户友好的错误消息。

让我们看一个例子,看看这有多有用。 Checkstyle Main类定义了-x--exclude-regexp exclude --exclude-regexp选项,该选项允许用于指定要排除的目录的多个正则表达式。

使用Commons CLI,您需要将在命令行上匹配的String值转换为应用程序java.util.regex.Pattern对象:

/*** Gets the list of exclusions from the parse results.* @param commandLine object representing the result of parsing the command line* @return List of exclusion patterns.*/
private static List<Pattern> getExclusions(CommandLine commandLine) {final List<Pattern> result = new ArrayList<>();if (commandLine.hasOption(OPTION_X_NAME)) {for (String value : commandLine.getOptionValues(OPTION_X_NAME)) {result.add(Pattern.compile(value));}}return result;
}

根据合同,在picocli中,您只需在List<Pattern> (或Pattern[]数组)字段上声明该选项。 由于picocli具有java.util.regex.Pattern的内置转换器,因此只需声明该选项即可。 转换代码完全消失了。 如果在命令行上指定了一个或多个-x选项,Picocli将实例化并填充列表。

/** Option that allows users to specify a regex of paths to exclude. */
@Option(names = {"-x", "--exclude-regexp"},description = "Regular expression of directory to exclude from CheckStyle")
private List<Pattern> excludeRegex;

选项名称

公用CLI

Commons CLI支持“短”和“长”选项,例如-t--tree 。 这并不总是您想要的。

Picocli允许选项具有任意数量的名称和任意前缀。 例如,这在picocli中是完全可以的:

@Option(names = {"-cp", "-classpath", "--class-path"})

位置参数

公用CLI

在Commons CLI中,您无法预先定义位置参数。 相反,其CommandLine解析结果类具有方法getArgs ,该方法以字符串数组形式返回位置参数。 Checkstyle Main类使用它来创建要处理的File对象的列表。

在picocli中, 位置参数是一等公民,例如命名选项。 不仅可以强类型化它们,而且位于不同位置的参数可以具有不同的类型,并且每个参数将在用法帮助消息中列出单独的条目和描述。

例如,Checkstyle Main类需要处理的文件列表,因此我们声明一个字段并使用@Parameters对其进行@Parametersarity = "1..*"属性意味着必须至少指定一个文件,否则picocli将显示有关缺少参数的错误消息。

@Parameters(paramLabel = "file", arity = "1..*", description = "The files to process")
private List<File> filesToProcess;

帮助选项

公用CLI

在Commons CLI中,用必需的选项创建一个具有--help选项的应用程序是非常困难的。 Commons CLI对帮助选项没有特殊处理,当用户指定<command> --help时,它将抱怨缺少必需的选项。

Picocli具有对常见(和自定义) 帮助选项的内置支持。

解析命令行参数

公用CLI

Commons CLI具有一个CommandLineParser接口,该接口带有parse方法,该方法返回代表解析结果的CommandLine 。 然后,应用程序调用CommandLine.hasOption(String)来查看是否设置了标志,或者调用CommandLine.hasOption(String) CommandLine.getOptionValue(String)来获取选项值。

Picocli在分析命令行参数时填充带注释的字段。 Picocli的parse…​方法也返回ParseResult可以上指定的选项并且什么的价值他们有,但大多数应用程序实际上并不需要使用查询ParseResult类,因为它们可以简单地检查该注入的注释值解析期间的字段。

处理结果

公用CLI

经营理念上白色隔离

解析器完成后,应用程序需要运行其业务逻辑,但首先要检查一些事情:

  • 是否需要版本信息或使用帮助? 如果是这样,请打印出所需的信息并退出。
  • 用户输入是否无效? 打印出一条包含详细信息的错误消息,打印使用帮助消息并退出。
  • 最终运行业务逻辑–处理业务逻辑引发的错误。

使用Commons CLI,这看起来像这样:

int exitStatus;
try {CommandLine commandLine = new DefaultParser().parse(buildOptions(), args);if (commandLine.hasOption(OPTION_VERSION)) { // --versionSystem.out.println("Checkstyle version: " + version());exitStatus = 0;} else if (commandLine.hasOption(OPTION_HELP)) { // --helpprintUsage(System.out);exitStatus = 0;} else {exitStatus = runBusinessLogic(); // business logic}
} catch (ParseException pex) { // invalid inputexitStatus = EXIT_WITH_CLI_VIOLATION;System.err.println(pex.getMessage());printUsage(System.err);
} catch (CheckstyleException ex) { // business logic exceptionexitStatus = EXIT_WITH_CHECKSTYLE_EXCEPTION_CODE;ex.printStackTrace();
}
System.exit(exitStatus);

Picocli提供了一些方便的方法来解决以上大部分问题。 通过使您的命令实现RunnableCallable ,应用程序可以专注于业务逻辑。 最简单地说,它可能看起来像这样:

public class Main implements Callable<Integer> {public static void main(String[] args) {CommandLine.call(new Main(), args);}public Integer call() throws CheckstyleException {// business logic here}
}

Checkstyle Main类需要控制退出代码,并且对错误处理有一些严格的内部要求,因此我们最终没有使用便捷方法,并且使解析结果处理与Commons CLI极为相似。 在picocli待办事项清单上可以改善这个领域。

使用帮助信息

Picocli在支持的平台上的使用帮助消息中使用ANSI颜色和样式。 这不仅看起来不错,而且还减轻了用户的认知负担 :对比度使重要的信息(如命令,选项和参数)从周围的文本中脱颖而出。

应用程序还可以在使用帮助消息的描述或其他部分中使用带有简单标记的ANSI颜色和样式,例如@|bg(red) text with red background|@ 。 请参阅用户手册的相关部分 。

对于CheckStyle,我们将其保持在最低限度,而CheckStyle的结果输出如下所示:

公用CLI

总结:最后的提示

请注意,即使使用帮助消息仅显示带有双连字符的选项,Commons CLI的默认解析器也可以识别单连字符( - )和双连字符( -- )长选项。 您需要确定是否继续支持此操作。

在picocli中@Option(names = "-xxx", hidden = true)如果您想模仿与Commons CLI完全相同的行为,则可以使用@Option(names = "-xxx", hidden = true)声明带有单个连字符的长选项:用法中未显示 picocli 中的隐藏选项帮助信息。

结论

从Commons CLI迁移到picocli可以为最终用户提供更好的用户体验,并且可以为开发人员带来显着的好处,即提高其可维护性和未来扩展的潜力。 迁移是手动过程,但相对简单。

更新:CheckStyle项目接受了本文更改中的拉取请求。 从CheckStyle 8.15开始,其命令行工具将使用picocli。 CheckStyle维护人员对结果感到满意:

Checkstyle从Apache CLI迁移到@picocli(将在8.15中发布),最后,CLI参数的文档现在已经以声明性的方式在代码中井井有条地组织起来,而Checkstyle的CLI遵循CLI最佳实践。

— CheckStyle维护者Roman Ivanov

翻译自: https://www.javacodegeeks.com/2018/11/migrating-commons-cli-picocli.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/344376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QuickBooks和Sage数据导出器

许多中小企业都使用QuickBooks作为其会计模块。 同样&#xff0c;许多公司也使用Sage进行会计处理。 他们中的大多数人在需要从这些系统中导出数据时会遇到问题。 在线提供的许多连接器价格昂贵&#xff0c;无法满足确切的要求。 随附的是一些简短的代码段&#xff0c;这些代码…

php内容缓存输出,PHP使用缓存即时输出内容(output buffering)的方法

PHP使用缓存即时输出内容(output buffering)的方法PHP使用缓存即时输出内容(output buffering)的方法。分享给大家供大家参考。具体如下&#xff1a;$buffer ini_get(output_buffering);echo str_repeat( ,$buffer1); //防止浏览器缓存ob_end_flush(); //关闭缓存for( $i1; $i…

继承能够访问父类私有字段_在单元测试中访问私有字段

继承能够访问父类私有字段首先&#xff0c;让我大声说一下&#xff0c;您需要将代码设计为可测试的&#xff0c;以便通过公共方法测试私有字段。 但是&#xff0c;&#xff08;“ buts”是人们仍在编程而不是计算机本身的原因&#xff0c;所以在这里很高兴&#xff09;有时您想…

甲骨文函数初探

我非常高兴有机会通过Cloud Native Limited Availability Program来测试Oracle功能。 去年&#xff0c;当我上次尝试在Oracle Groundbreaker APAC巡回赛中在Oracle Cloud中运行无服务器功能时&#xff0c;有两种选择。 您可以在虚拟机中运行我自己的Fn服务器&#xff0c;也可以…

spring roo_使用Spring Roo进行概念验证

spring roo在Keyhole工作期间&#xff0c;我参与了许多项目&#xff0c;其中客户要求我们重写旧系统&#xff0c;同时保留其现有数据库。 有时&#xff0c;它有助于快速演示如何使用当前技术来简化开发&#xff0c;测试和维护其代码。 我发现可以创建一个快速示例&#xff08;…

oracle虚拟机怎么装系统,Virtualbox怎么安装系统 VirtualBox虚拟机安装Win8系统教程 (3)...

三、对新建的虚拟机做重要的设定&#xff1a;1、在Oracle VM VirtualBox里面点击下刚才建好的虚拟机&#xff0c;然后点下上面的黄色图标“设置”&#xff0c;或者右键菜单里面点击设置也可以(快捷键是CtrlS)Oracle VM VirtualBox虚拟机设置2、在出来的设置页面里面&#xff0c…

oracle xe gentoo,Oracle在gentoo下安装

补充:解决ORACLE10G安装界面中文乱码问题&#xff0c;修改以下变量使安装界面为英文。export LC_CTYPEen_US.UTF-8以下为原文1.OS:Gentoo-linux-2.6.23-rc5Oracle:Oracle Database 10g Release 2 (10.2.0.1.0) for Linux x86下载地址&#xff1a;2.使用管理员账户建立Oracle用户…

JMetro 5.2版发布

再一次问好 JMetro的新更新刚刚发布。 添加了两种新的控件样式&#xff1a;“标题窗格”和“手风琴”。 此外&#xff0c;还对现有样式和错误修复进行了调整。 最终&#xff0c;JMetro现在也可以通过Maven Central获得。 在本文中&#xff0c;我将详细介绍刚刚发布的JMetro 5…

matlab处理svm的数据,SVM-GUI 使用支持向量机(SVM)算法进行处理数据,提取特征参数,并通过MATLAB界面显示相关数 238万源代码下载- www.pudn.com...

文件名称: SVM-GUI下载收藏√ [5 4 3 2 1 ]开发工具: matlab文件大小: 231 KB上传时间: 2014-05-13下载次数: 13提 供 者: 幽灵详细说明&#xff1a;使用支持向量机(SVM)算法进行处理数据&#xff0c;提取特征参数&#xff0c;并通过MATLAB界面显示相关数据-Using Support…

mockito_Eclipse的Mockito模板

mockito有时候&#xff0c;我想念树林里的树木-那是一段令人不安的长时间。 我最近才再次意识到这一点&#xff0c;在无数次中键入了一个更详细的模仿表达式之一。 有问题的语句是一个doAnswer(Answer)构造&#xff0c;使用涉及到的静态导入和泛型代码进行编码总是很麻烦。 尽…

linux系统运行powerbi,使用 Power BI 服务 - Power BI | Microsoft Docs

快速入门 - 使用 Power BI 服Quickstart - Getting around in Power BI service10/12/2020本文内容备注Power BI 正在转换为新外观&#xff0c;文档中的某些图像可能与服务中显示的图像不匹配。Power BI is moving to a new look, and some images in the documentation may no…

JMetro版本4.8已发布

再一次问好&#xff01; JMetro Java 4.8版JavaFX主题刚刚发布。 我们即将接近下一个主要版本的版本5.0。 这是已经过彻底改造的旧样式&#xff1a; 日期选择器 树视图 以及经过调整或更改了CSS结构的旧版本&#xff1a; 表格检视 列表显示 组合框 评级控制 4.8版详细…

Java 11快多少?

尽管大多数开发人员仍然使用Java 8 &#xff0c;但Java 11还是在不久前发布的。 让我们看看其中哪个对OptaPlanner更快。 找出答案的最佳方法当然是运行OptaPlanner基准测试。 本文是我们针对Java 8的类似文章的后续文章 。 基准方法 为了运行基准测试&#xff0c;我们使用了&…

linux5.9安装教程,Linux内核5.9的最重要功能及安装方法

原标题&#xff1a;Linux内核5.9的最重要功能及安装方法Linux内核5.9带来了吸引数据中心管理员的诸多性能提升。本文作者着重介绍了改进之处&#xff0c;并介绍了如何安装主线内核。与5.8一样&#xff0c;Linux内核5.9确实没有任何改变游戏规则的功能&#xff0c;至少对普通用户…

Apache Payara:让我们加密

不久前&#xff0c;我写了一个小教程 &#xff0c;介绍如何生成“让我们加密SSL”证书并将其安装在Glassfish Java EE平台上。 这个技巧对我来说是一个奇迹&#xff0c;但是每三个月必须手动更新和重新安装证书变得很烦人。 我做了一些研究&#xff0c;并且与第一个教程一样&a…

openssh arm linux 编译,openssh编译安装到ARM嵌入式系统中

目录一&#xff0e;SSHD编译(此步骤在虚拟机上执行)1.1 在/root/目录下创建ssh目录1.2 交叉编译zlib1.3交叉编译openssl1.4交叉编译openssh二&#xff0e;移植(此步骤在开发板上执行)2.1 在开发板上建立需要的目录2.2 下面是在开发板上操作2.3修改sshd_config三、加入自启动脚本…

linux gui编程语言,使用 Red 语言编写 GUI 应用程序

一句话概括 — 使用 Red 语言编写原生跨平台桌面 GUI。尝试在 Windows 上使用 PyInstaller 将“可执行”的 ducktape 封装在 Python 脚本之后&#xff0c;我发现应该学习的编程语言类应该具有以下属性&#xff1a;静态二进制编译(产生一个二进制&#xff0c;不是运行时的字节码…

对c语言字符数组描述错误的是,下述对C语言字符数组的描述中错误的是( )。

摘要&#xff1a;条形图用频率值型来表分组分布示数数据&#xff0c;下述没有相邻之间间隔竖条。中国:在中大学列联分析&#xff0c;字符百分表的条件正确关于的是方向说法。条形图用频率值型来表分组分布示数数据&#xff0c;数组述中没有相邻之间间隔竖条。...条形图用频率值…

android 实现自动拍照,Android自定义相机实现定时拍照功能

这篇博客为大家介绍Android自定义相机&#xff0c;并且实现倒计时拍照功能。首先自定义拍照会用到SurfaceView控件显示照片的预览区域&#xff0c;以下是布局文件&#xff1a;activity_main.xmlandroid:layout_width"match_parent"android:layout_height"match_…

android版本8.1.0和9的区别,安卓8.1和9.0的区别是什么

安卓8.1和9.0的主要差别是&#xff1a;流畅度、耗电量、功能等等方面的不同。在手机配置足够的情况下&#xff0c;9.0要比8.1更流畅和省电&#xff0c;它可以同时让后台保持更多APP&#xff0c;每个APP运行的时候更加流畅&#xff0c;其新的智能电量管理功能、暗黑模式让手机更…