java 如何让picocli解析`"--item --item foo”`为`[null,“foo”]` `:List< String>`

00jrzges  于 2023-04-10  发布在  Java
关注(0)|答案(2)|浏览(135)

我有一个名为--msg-content-list-item的参数

public class CliProtonJ2Sender implements Callable<Integer> {

    @CommandLine.Option(
        names = {"--msg-content-list-item"},
        arity = "0..1",
        defaultValue = CommandLine.Option.NULL_VALUE)
    private List<String> msgContentListItem;

    // ...
}

我希望下面的测试通过

@Test
    void test_msgContentListItem() {
        CliProtonJ2Sender a = new CliProtonJ2Sender();
        CommandLine b = new CommandLine(a);
        CommandLine.ParseResult r = b.parseArgs("--msg-content-list-item", "--msg-content-list-item", "pepa");

        // https://github.com/powermock/powermock/wiki/Bypass-Encapsulation
        List<String> v = Whitebox.getInternalState(a, "msgContentListItem", a.getClass());
        assertThat(v).containsExactly(null, "pepa");
    }

但事实并非如此

missing (1): null
---
expected   : [null, pepa]
but was    : [pepa]

如何定义@CommandLine.Option以实现所需的行为?

2w3kk1z5

2w3kk1z51#

我怀疑这是一个bug/不便之处。

// now process the varargs if any
            String fallback = consumed == 0 && argSpec.isOption() && !OptionSpec.DEFAULT_FALLBACK_VALUE.equals(((OptionSpec) argSpec).fallbackValue())
                    ? ((OptionSpec) argSpec).fallbackValue()
                    : null;
            if (fallback != null && (args.isEmpty() || !varargCanConsumeNextValue(argSpec, args.peek()))) {
                args.push(fallback);
            }

由于((OptionSpec) argSpec).fallbackValue()返回null,因此可以理解为不存在fallbackValue,因此if (fallback != null不会将回退值推送到args

变通方案

定义您自己的fallbackValue魔术字符串和一个稍后将其转换为nullconverter。转换器在consumeArguments完成后运行(使用failbackValue)。

public static final String MY_NULL_VALUE = "MY_" + CommandLine.Option.NULL_VALUE;

public class MyNullValueConvertor implements CommandLine.ITypeConverter<String> {
    @Override
    public String convert(String value) throws Exception {
        if (value.equals(MY_NULL_VALUE)) {
            return null;
        }
        return value;
    }
}
@CommandLine.Option(
        names = {"--msg-content-list-item"},
        arity = "0..1", fallbackValue = MY_NULL_VALUE,
        converter = MyNullValueConvertor.class)
    private List<String> msgContentListItem;
s4n0splo

s4n0splo2#

有一个bug,现在已修复。
在版本4.7.2之前,请使用我的其他答案中的解决方法。
从picocli 4.7.2开始,像这样使用failbackValue

@Option(names = {"--list"}, arity = "0..1", fallbackValue = CommandLine.Option.NULL_VALUE)
List<String> list;

来自https://github.com/remkop/picocli/blob/2944addb8ba34d2ee6f97564bd43128bb62ec382/src/test/java/picocli/FallbackTest.java#L192-L193

相关问题