Picocli is a modern framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It supports colors, autocompletion, subcommands, and more. In 1 source file so apps can include as source & avoid adding a dependency. Written in Java, usable from Groovy, Kotlin, Scala, etc.
At the moment, the Spring Boot starter requires you to write some boilerplate to identify your "main" command in the form of a CommandLineRunner.
I always feel a bit sad when I had to add that into each new application I write on top of Picocli so I've been thinking of ways to remove that boilerplate and have come up with the following:
public class PicocliApplicationRunner implements CommandLineRunner, ExitCodeGenerator {
private final ApplicationContext context;
private final IFactory factory;
private int exitCode;
public PicocliApplicationRunner(ApplicationContext context, IFactory factory) {
this.context = context;
this.factory = factory;
}
@Override
public void run(String... args) {
Collection<Object> commands = context.getBeansWithAnnotation(Command.class).values();
Set<Class<?>> subCommandClasses = commands.stream()
.map(Object::getClass)
.map(c -> c.getAnnotation(Command.class))
.map(Command::subcommands)
.flatMap(Arrays::stream)
.collect(Collectors.toSet());
List<Object> mainCommands = commands.stream()
.filter(c -> !subCommandClasses.contains(c.getClass()))
.collect(Collectors.toList());
if (mainCommands.size() < 1) {
throw new CommandLine.InitializationException("No main command bean can be found");
} else if (mainCommands.size() > 1) {
throw new CommandLine.InitializationException("Multiple main command beans found");
}
exitCode = new CommandLine(mainCommands.get(0), factory).execute(args);
}
@Override
public int getExitCode() {
return exitCode;
}
}
What do you think? I am happy to raise a PR if you like this idea to do at least the following:
Add the above class
Perhaps add a marker interface e.g. PicocliRunner, which is then implemented by the above. Then make the @Bean conditional on missing beans in order to allow users to override the implementation if they want.
Update any relevant documentation
I've tested and this works fine in at least simple cases but if there are any more advanced setups that you think this might not work for, please let me know.
At the moment, the Spring Boot starter requires you to write some boilerplate to identify your "main" command in the form of a CommandLineRunner.
I always feel a bit sad when I had to add that into each new application I write on top of Picocli so I've been thinking of ways to remove that boilerplate and have come up with the following:
What do you think? I am happy to raise a PR if you like this idea to do at least the following:
I've tested and this works fine in at least simple cases but if there are any more advanced setups that you think this might not work for, please let me know.