从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,一经查实,立即删除!

相关文章

怎么设置php的css颜色代码,CSS的文本字体颜色如何设置

这里要介绍的是网页设置颜色包含有哪些&#xff1b;网页颜色规定规范。1、常用颜色地方包含&#xff1a;字体颜色、超链接颜色、网页背景颜色、边框颜色2、颜色规范与颜色规定&#xff1a;网页使用RGB模式颜色网页中颜色的运用是网页必不可少的一个元素。使用颜色目的在于有区别…

QuickBooks和Sage数据导出器

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

php+easyui+上传文件,easyui 上传文件代码

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.IO;using BLL;using m Model;using System.Data;using System.Data.SqlClient;using System.Text;namespace Web.Handler{/// /// AddOppportunityHandler 的摘要说明/// pub…

java 8 集合分组_Java 8:按集合分组

java 8 集合分组在继续阅读Venkat Subramaniam的“ Java函数式编程 ”时&#xff0c;我到达了介绍Stream&#xff03;collect函数的那部分。 我们想收集一个人&#xff0c;按年龄分组并返回一张方便的地图&#xff08;年龄->人的名字&#xff09;。 要刷新&#xff0c;这是…

请编写一个php程序,(笔试题)php练习笔试题(一) 编写程序(请任选两题)

简答题1.写出5个以上你所知道的常用的Linux命令和它的功能cat&#xff0c;显示文件内容。cd&#xff0c;改变目录路径。cp&#xff0c;复制文件。find&#xff0c;查找文件。grep&#xff0c;搜索、过滤信息。ls&#xff0c;列出目录信息。more&#xff0c;分页显示。rm&#x…

python str translate,str.translate() --文本过滤和处理

问题: 想清除整个范围的字符&#xff0c;或者去掉音符1、使用str.translate()s python\fis\tawesome\r\n# 第一步是清理空格&#xff0c;可以先建立一个小型的转换表&#xff0c;然后使用reanslate()方法remap {ord(\t): ,ord(\f): ,ord(\r): None}a s.translate(remap)aO…

MicroProfile 2.2 BOM导入支持

MicroProfile 2.2刚刚发布&#xff0c;其中包含对Fault Tolerance&#xff0c;Open Tracing&#xff0c;Open API和Rest Client API的更新。 自2.2版以来&#xff0c;还支持使用BOM&#xff08;物料清单&#xff09;依赖项导入。 通过这种方法&#xff0c;我们可以在dependenc…

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;有时您想…

php模拟论坛,模仿OSO的论坛(二)

模仿OSO的论坛(二)2006-10-09 00:00:00 作者&#xff1a;模仿OSO的论坛(二)read.php(用来显示相关主题内容)疑难问题主 题&#xff1a;color#993333>include "connect.inc.php";$query "select * from guestbook where id".$theme_id;$res mysql_quer…

甲骨文函数初探

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

oracle 邻接模型,【原创】MySQL 模拟Oracle邻接模型树形处理

数据库对层次结构的处理模型有好多种&#xff0c;可以根据自己的需求来设计模型&#xff0c;当然最简单的也是最容易设计的模型就是所谓的邻接模型。在这方面&#xff0c;其他数据库比如Oracle提数据库对层次结构的处理模型有好多种&#xff0c;可以根据自己的需求来设计模型&a…

json字符串导入oracle,如何在Oracle中将JSON字符串转换为JSON

我需要在Oracle查询中将JSON字符串转换为JSON。示例字符串&#xff1a;{"1":{"qid":1,"aid":1,"a":"Yes","isdyn":0},"2":{"qid":2,"aid":7,"a":"sdfbsjkb",&…

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

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

【渝粤教育】电大中专药物分析技术基础作业 题库

1.《中国药典》规定“称定”时&#xff0c;指称取重量应准确至所取重量的 A.10% B.1.95&#xff5e;2.05g C.百分之一 D.1.5&#xff5e;2.5g E.千分之一 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;未作答 2.2℃&#xff5e;10℃指 A.密闭 B.密封 C.阴凉处 D.冷处…

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

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

JDK 12的Files.mismatch方法

JDK 12向Files类引入了一种新方法。 方法Files.mismatch(Path,Path)已通过JDK-8202302引入JDK 12&#xff0c;并在JDK 12 Early Access Build 20 &#xff08;支持新{systemProperty} Javadoc标记的相同早期访问版本&#xff09;中可用 。 JDK-8202302 [“用于比较文件的&…

【渝粤教育】电大中专计算机网络基础 (2)作业 题库

1通信中产生和发送信息的一端叫做&#xff08;&#xff09;。 A信源 B信宿 C信道 D噪声 正确 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2通信中接收信息的一端叫做&#xff08;&#xff09;。 A信源 B信宿 C信道 D噪声 正确 正确答案&#xff1a;左边查询 学生答案…

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用户…

【渝粤教育】电大中专跨境电子商务理论与实务 (11)作业 题库

1.在按照交易主体类型中&#xff0c;&#xff08; &#xff09;面对的最终客户为企业或集团客户&#xff0c;提供企业、产品、服务等相关信息。 A.O2O跨境电商或平台 B.B2B跨境电商或平台 C.B2C跨境电商或平台 D.C2C跨境电商或平台 错误 正确答案&#xff1a;左边查询 学生答案…