为什么picocli即使在默认多重性为0..1的情况下,也要求ArgGroup中的args?

时间:2019-10-27 04:33:08

标签: picocli

您可以在此处找到代码示例。 Link to my GitHub project

在Driver.java文件中,您可以看到我指定了一个排他的ArgGroup。根据文档,我的理解是默认多重性是0.1.1。该文档指出:“默认值为multiplicity =“ 0..1”,这意味着默认情况下可以省略或指定一次组。”

我还尝试将多重性显式设置为0..1,但这并没有改变行为。运行不带-al或-rl选项的程序,解析将引发NullPointerException。该框架的行为似乎是其中之一。这与documentation不符。如果需要,我应该只能使用-n选项运行该程序。我希望ArgGroup是完全可选的。

git枢纽链接处的程序是一个功能全面的maven项目,可以克隆,构建和运行。但是,这是堆栈跟踪。没有指定参数或没有arg组。我希望在没有任何参数的情况下将打印用法信息。另外,该组的默认多重性应为0..1,因此我不必在arg组中指定一个选项。

java.lang.NullPointerException
    at com.shawnfox.java4.concurrency.Driver.call(Driver.java:58)
    at com.shawnfox.java4.concurrency.Driver.call(Driver.java:1)
    at picocli.CommandLine.executeUserObject(CommandLine.java:1743)
    at picocli.CommandLine.access$900(CommandLine.java:145)
    at picocli.CommandLine$RunLast.handle(CommandLine.java:2101)
    at picocli.CommandLine$RunLast.handle(CommandLine.java:2068)
    at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:1935)
    at picocli.CommandLine.execute(CommandLine.java:1864)
    at com.shawnfox.java4.concurrency.Driver.main(Driver.java:50)

1 个答案:

答案 0 :(得分:1)

感谢您添加堆栈跟踪。我看到NullPointerException发生在line 58call方法中,而不是picocli本身。

所以问题不在于picocli需要可选的(multiplecity = 0..1)参数组中的选项,问题在于call方法假定带有@ArgGroup注释的字段将即使组中没有选项匹配,也总是初始化。这个假设是错误的。

发生的事情是,如果在命令行上既未指定-al选项也未指定-rl选项,则SynchronizationOptions参数组根本不匹配,因此picocli将不会实例化SynchronizationOptions对象,并且synchOptions field on line 32将不会初始化。

这是picocli解析器与参数组一起工作的方式:例如,对于具有多重性*的组,picocli将为每个组匹配创建用户对象的实例,并将其添加到带注释的集合/数组中字段。

如果没有匹配的组,则该用户对象的实例将为零。这使应用程序可以准确地检测出该组是否匹配-如果该组匹配,则该应用程序可以依赖于唯一组 的不变性。 option已匹配并具有值,并且对于同现组 all 选项已匹配并具有命令行中的值。 (如果picocli实例化不匹配的用户对象,则不可能。)

解决方案是将应用程序更改为检查null或初始化应用程序中的synchOptions字段。后者可能是最简单,最干净的。例如,替换:

@ArgGroup(exclusive = true)
SynchronizationOptions synchOptions;

@ArgGroup(exclusive = true)
SynchronizationOptions synchOptions = new SynchronizationOptions();

然后synchOptions永远不会null,因此应用程序可以安全地在call方法中引用其字段:

public Void call() {
    if (synchOptions.useReentrantLock) {
        // ...

或者,检查是否使用synchOptions == null方法中的call。这样,应用程序可以检测是否有任何同步选项匹配,如果匹配,则应用程序可以依赖以下事实:至少一个布尔字段为true