Reputation: 28889
I have a parameter named --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;
// ...
}
I wish for the following test to pass
@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");
}
But it doesn't and I get
missing (1): null
---
expected : [null, pepa]
but was : [pepa]
How do I define @CommandLine.Option
to behave the way I want?
Upvotes: 0
Views: 220
Reputation: 28889
There was a bug which is now fixed.
Prior to version 4.7.2, use the workaround in my other answer.
As of picocli 4.7.2, use the fallbackValue
like this
@Option(names = {"--list"}, arity = "0..1", fallbackValue = CommandLine.Option.NULL_VALUE)
List<String> list;
Upvotes: 0
Reputation: 28889
I suspect this is a bug/inconvenience. In method consumeArguments
, at https://github.com/remkop/picocli/blob/main/src/main/java/picocli/CommandLine.java
// 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);
}
Because ((OptionSpec) argSpec).fallbackValue()
returns null
, it is understood as if there was no fallbackValue
, and therefore the if (fallback != null
does not push the fallback value to args
.
Define your own fallbackValue
magic string and a converter
that later converts it to null
. The convertor runs after consumeArguments
completes (with the 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;
Upvotes: 0