Skip to content

Options with primitive types fail in 4.0 without explicit value #1262

@ThomasVitale

Description

@ThomasVitale

Before Spring Shell 4.0, boolean command options would default to false if not specified when executing the command. In 4.0, they fail instead with the following error message:

Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [boolean] for value [null]
        at org.springframework.core.convert.support.GenericConversionService.assertNotPrimitiveTargetType(GenericConversionService.java:300)
        at org.springframework.core.convert.support.GenericConversionService.handleResult(GenericConversionService.java:293)
        at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182)
        at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:165)
        at org.springframework.shell.core.command.adapter.MethodInvokerCommandAdapter.prepareArguments(MethodInvokerCommandAdapter.java:166)
        at org.springframework.shell.core.command.adapter.MethodInvokerCommandAdapter.doExecute(MethodInvokerCommandAdapter.java:90)
        at org.springframework.shell.core.command.AbstractCommand.execute(AbstractCommand.java:162)
        at org.springframework.shell.core.command.CommandExecutor.execute(CommandExecutor.java:71)
        ... 28 more
Caused by: java.lang.IllegalArgumentException: A null value cannot be assigned to a primitive type
        ... 36 more

So, a command definition like the following with Spring Shell 3.4:

    @Command(name = "test", description = "Test command.")
    public void build(
        @Option(description = "Perform a clean build.") boolean clean,
    ) {
        ...
    }

would need to change to the following in 4.0:

    @Command(name = "test", description = "Test command.")
    public void build(
        @Option(description = "Perform a clean build.", defaultValue = "false", longName = "clean") boolean clean,
    ) {
        ...
    }

That's counterintuitive because in Java the primitive type boolean is always false if unspecified.

Furthermore, when providing the option at execution time, a value is also required. This bit is mentioned in the docs, but it would be great to highlight that in the migration guide as a breaking change since it completely change the user experience.

It's common for CLIs to pass boolean options to a command without a value, meaning it's "true". Any chance the previous behaviour could be restored? This breaking change doesn't affect only developers when upgrading to 4.0, but also all users of CLIs implemented with Spring Shell, having to change commands like:

mycli test --clean

to:

mycli test --clean true

This is where the check is implemented:

if (shortName == ' ' && longName.isEmpty()) {
throw new IllegalArgumentException(
"Either shortName or longName (or both) must be provided for option on parameter '"
+ parameter.getName() + "'");
}

I'm available to help with a potential PR.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions