为什么 picocli 需要 ArgGroup 中的参数,即使默认多重性为 0..1?
Why is picocli requiring args within an ArgGroup even with the default multiplicity of 0..1?
您可以在此处找到代码示例。
Link to my GitHub project
在文件Driver.java中,可以看到我指定了一个独占的ArgGroup。我根据文档的理解是默认的多重性是 0..1。文档指出,"The default is multiplicity = "0..1",这意味着默认情况下可以省略或指定一个组。
我也曾尝试将多重性显式设置为 0..1,但这并没有改变行为。 运行 没有 -al 或 -rl 选项的程序,解析会抛出 NullPointerException。该框架的行为就好像这些选项之一是必需的。那是不符合documentation的。如果我愿意,我应该能够 运行 这个程序只用 -n 选项。我希望 ArgGroup 完全可选。
git 中心 link 的程序是一个功能齐全的 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.access0(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)
感谢您添加堆栈跟踪。我看到 NullPointerException
出现在 line 58 的 call
方法中,而不是 picocli 本身。
所以问题不在于 picocli 需要可选的 (multiplicity = 0..1
) 参数组中的选项,问题在于 call
方法假定 @ArgGroup
-注释字段将始终被初始化,即使组中没有匹配的选项。这个假设是不正确的。
发生的情况是,如果在命令行中既没有指定 -al
选项也没有指定 -rl
选项,那么 SynchronizationOptions
参数组根本就没有匹配项,所以 picocli 不会实例化 SynchronizationOptions
对象,并且 synchOptions
field on line 32 不会被初始化。
这就是 picocli 解析器处理参数组的方式:例如,对于具有多重性的组 *
,picocli 将为每个组匹配创建一个用户对象实例,并将其添加到带注释的 collection/array字段。
如果没有组匹配,则用户对象的实例为零。这允许应用程序准确检测组是否匹配 - 如果组 是 匹配,应用程序可以依赖于排他组 的不变量一个 选项匹配并具有值,并且对于同现组 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) {
// ...
或者,检查call
方法中是否有synchOptions == null
。这允许应用程序检测是否有任何同步选项匹配,如果匹配,应用程序可以依赖至少一个布尔字段是 true
.
这一事实
您可以在此处找到代码示例。 Link to my GitHub project
在文件Driver.java中,可以看到我指定了一个独占的ArgGroup。我根据文档的理解是默认的多重性是 0..1。文档指出,"The default is multiplicity = "0..1",这意味着默认情况下可以省略或指定一个组。
我也曾尝试将多重性显式设置为 0..1,但这并没有改变行为。 运行 没有 -al 或 -rl 选项的程序,解析会抛出 NullPointerException。该框架的行为就好像这些选项之一是必需的。那是不符合documentation的。如果我愿意,我应该能够 运行 这个程序只用 -n 选项。我希望 ArgGroup 完全可选。
git 中心 link 的程序是一个功能齐全的 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.access0(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)
感谢您添加堆栈跟踪。我看到 NullPointerException
出现在 line 58 的 call
方法中,而不是 picocli 本身。
所以问题不在于 picocli 需要可选的 (multiplicity = 0..1
) 参数组中的选项,问题在于 call
方法假定 @ArgGroup
-注释字段将始终被初始化,即使组中没有匹配的选项。这个假设是不正确的。
发生的情况是,如果在命令行中既没有指定 -al
选项也没有指定 -rl
选项,那么 SynchronizationOptions
参数组根本就没有匹配项,所以 picocli 不会实例化 SynchronizationOptions
对象,并且 synchOptions
field on line 32 不会被初始化。
这就是 picocli 解析器处理参数组的方式:例如,对于具有多重性的组 *
,picocli 将为每个组匹配创建一个用户对象实例,并将其添加到带注释的 collection/array字段。
如果没有组匹配,则用户对象的实例为零。这允许应用程序准确检测组是否匹配 - 如果组 是 匹配,应用程序可以依赖于排他组 的不变量一个 选项匹配并具有值,并且对于同现组 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) {
// ...
或者,检查call
方法中是否有synchOptions == null
。这允许应用程序检测是否有任何同步选项匹配,如果匹配,应用程序可以依赖至少一个布尔字段是 true
.