It seems that custom "Converter<S, T>"-Beans are not registered correctly when running a SpringBoot-Application and SpringShell. I have attached a full working project with test-cases demonstrating the problem: shell.zip
In the previous 3.x-line of SpringShell this was not a issue.
In a nutshell:
We have commands in the form:
@Command(name = "custom")
public void custom(
@Option(longName = "msg", required = true) Message msg) {
System.out.println(msg.toString());
}
In a Component we define a new Bean implementiung the Converter-Interface. This is initialized from SpringBoot before running the actual command - and yet the Converter cannot be found from the CommandExecutor:
org.springframework.shell.core.command.CommandExecutionException: Unable to execute command custom
at org.springframework.shell.core.command.CommandExecutor.execute(CommandExecutor.java:74) ~[spring-shell-core-4.0.2.jar:4.0.2]
at org.springframework.shell.core.NonInteractiveShellRunner.executeCommand(NonInteractiveShellRunner.java:158) ~[spring-shell-core-4.0.2.jar:4.0.2]
at org.springframework.shell.core.NonInteractiveShellRunner.run(NonInteractiveShellRunner.java:95) ~[spring-shell-core-4.0.2.jar:4.0.2]
at org.springframework.shell.core.autoconfigure.ShellRunnerAutoConfiguration.lambda$springShellApplicationRunner$0(ShellRunnerAutoConfiguration.java:39) ~[spring-shell-core-autoconfigure-4.0.2.jar:4.0.2]
at org.springframework.boot.SpringApplication.lambda$callRunner$0(SpringApplication.java:788) ~[spring-boot-4.0.6.jar:4.0.6]
at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:82) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:86) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) ~[spring-boot-4.0.6.jar:4.0.6]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:788) ~[spring-boot-4.0.6.jar:4.0.6]
at org.springframework.boot.SpringApplication.lambda$callRunners$0(SpringApplication.java:776) ~[spring-boot-4.0.6.jar:4.0.6]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:na]
at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:776) ~[spring-boot-4.0.6.jar:4.0.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:328) ~[spring-boot-4.0.6.jar:4.0.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1365) ~[spring-boot-4.0.6.jar:4.0.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-4.0.6.jar:4.0.6]
at shell.SpringShellApplication.main(SpringShellApplication.java:14) ~[classes/:na]
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [shell.SpringShellApplication$Message]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:289) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:184) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:165) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.shell.core.command.adapter.MethodInvokerCommandAdapter.prepareArguments(MethodInvokerCommandAdapter.java:153) ~[spring-shell-core-4.0.2.jar:4.0.2]
at org.springframework.shell.core.command.adapter.MethodInvokerCommandAdapter.doExecute(MethodInvokerCommandAdapter.java:93) ~[spring-shell-core-4.0.2.jar:4.0.2]
at org.springframework.shell.core.command.AbstractCommand.execute(AbstractCommand.java:166) ~[spring-shell-core-4.0.2.jar:4.0.2]
at org.springframework.shell.core.command.CommandExecutor.execute(CommandExecutor.java:71) ~[spring-shell-core-4.0.2.jar:4.0.2]
... 23 common frames omitted
From my point of view this should be possible as it is standard Spring-Behaviour to support "Converters".
Additional note: When registering the Command programmitically the Converters are respected. It seems to me, that the Building-process of the Commands via Annotations is the problem.
@Bean
org.springframework.shell.core.command.Command programmatic() {
Consumer<CommandContext> action = ctx ->
System.out.println(ctx.getOptionByName("msg"));
return org.springframework.shell.core.command.Command
.builder()
.name("programmatic")
.options(
CommandOption.with()
.longName("msg")
.type(Message.class).build())
.execute(action);
}
``
It seems that custom "Converter<S, T>"-Beans are not registered correctly when running a SpringBoot-Application and SpringShell. I have attached a full working project with test-cases demonstrating the problem: shell.zip
In the previous 3.x-line of SpringShell this was not a issue.
In a nutshell:
We have commands in the form:
In a Component we define a new Bean implementiung the Converter-Interface. This is initialized from SpringBoot before running the actual command - and yet the Converter cannot be found from the CommandExecutor:
From my point of view this should be possible as it is standard Spring-Behaviour to support "Converters".
Additional note: When registering the Command programmitically the Converters are respected. It seems to me, that the Building-process of the Commands via Annotations is the problem.