Quarkus - Command Mode with Picocli

    Quarkus provides support for using Picocli. This guide contains examples of extension usage.

    If you are not familiar with the Quarkus Command Mode, consider reading the Command Mode reference guide first.

    This will add the following to your pom.xml:

    1. <dependency>
    2. <groupId>io.quarkus</groupId>
    3. <artifactId>quarkus-picocli</artifactId>
    4. </dependency>

    Simple command line application

    Simple PicocliApplication with only one Command can be created as follows:

    1. package com.acme.picocli;
    2. import picocli.CommandLine;
    3. import javax.enterprise.context.Dependent;
    4. import javax.inject.Inject;
    5. @CommandLine.Command (1)
    6. public class HelloCommand implements Runnable {
    7. @CommandLine.Option(names = {"-n", "--name"}, description = "Who will we greet?", defaultValue = "World")
    8. String name;
    9. private final GreetingService greetingService;
    10. public HelloCommand(GreetingService greetingService) { (2)
    11. this.greetingService = greetingService;
    12. }
    13. @Override
    14. public void run() {
    15. greetingService.sayHello(name);
    16. }
    17. }
    18. @Dependent
    19. class GreetingService {
    20. void sayHello(String name) {
    21. System.out.println("Hello " + name + "!");
    22. }
    23. }
    Beans with @CommandLine.Command should not use proxied scopes (e.g. do not use @ApplicationScope) because Picocli will not be able set field values in such beans. This extension will register classes with @CommandLine.Command annotation using @Depended scope. If you need to use proxied scope, then annotate setter and not field, for example:

    Command line application with multiple Commands

    When multiple classes have the picocli.CommandLine.Command annotation, then one of them needs to be also annotated with io.quarkus.picocli.runtime.annotations.TopCommand. This can be overwritten with the quarkus.picocli.top-command property.

    1. package com.acme.picocli;
    2. import io.quarkus.picocli.runtime.annotations.TopCommand;
    3. import picocli.CommandLine;
    4. @TopCommand
    5. @CommandLine.Command(mixinStandardHelpOptions = true, subcommands = {HelloCommand.class, GoodByeCommand.class})
    6. }
    7. @CommandLine.Command(name = "hello", description = "Greet World!")
    8. class HelloCommand implements Runnable {
    9. @Override
    10. public void run() {
    11. System.out.println("Hello World!");
    12. }
    13. }
    14. @CommandLine.Command(name = "goodbye", description = "Say goodbye to World!")
    15. class GoodByeCommand implements Runnable {
    16. @Override
    17. public void run() {
    18. System.out.println("Goodbye World!");
    19. }
    20. }

    You can customize CommandLine classes used by the picocli extension by producing your own bean instance:

    1. package com.acme.picocli;
    2. import io.quarkus.picocli.runtime.PicocliCommandLineFactory;
    3. import io.quarkus.picocli.runtime.annotations.TopCommand;
    4. import picocli.CommandLine;
    5. import javax.enterprise.context.ApplicationScoped;
    6. import javax.enterprise.inject.Produces;
    7. @TopCommand
    8. @CommandLine.Command
    9. public class EntryCommand implements Runnable {
    10. @CommandLine.Spec
    11. CommandLine.Model.CommandSpec spec;
    12. @Override
    13. public void run() {
    14. System.out.println("My name is: " + spec.name());
    15. }
    16. }
    17. @ApplicationScoped
    18. class CustomConfiguration {
    19. @Produces
    20. CommandLine customCommandLine(PicocliCommandLineFactory factory) { (1)
    21. return factory.create().setCommandName("CustomizedName");
    22. }
    23. }

    Different entry command for each profile

    1You can return instance of java.lang.Class here. In such case CommandLine will try to instantiate this class using CommandLine.IFactory.

    Configure CDI Beans with parsed arguments

    You can use Event<CommandLine.ParseResult> or just CommandLine.ParseResult to configure CDI beans based on arguments parsed by Picocli. This event will be generated in QuarkusApplication class created by this extension. If you are providing your own @QuarkusMain this event will not be raised. CommandLine.ParseResult is created from default CommandLine bean.

    1. @CommandLine.Command
    2. public class EntryCommand implements Runnable {
    3. String connectionString;
    4. @Inject
    5. DataSource dataSource;
    6. @Override
    7. public void run() {
    8. try (Connection c = dataSource.getConnection()) {
    9. // Do something
    10. } catch (SQLException throwables) {
    11. // Handle error
    12. }
    13. }
    14. }
    15. @ApplicationScoped
    16. class DatasourceConfiguration {
    17. @Produces
    18. @ApplicationScoped (1)
    19. DataSource dataSource(CommandLine.ParseResult parseResult) {
    20. PGSimpleDataSource ds = new PGSimpleDataSource();
    21. ds.setURL(parseResult.matchedOption("c").getValue().toString());
    22. return ds;
    23. }
    24. }

    You can also provide your own application entry point annotated with QuarkusMain (as described in ).

    1. package com.acme.picocli;
    2. import io.quarkus.runtime.QuarkusApplication;
    3. import io.quarkus.runtime.annotations.QuarkusMain;
    4. import picocli.CommandLine;
    5. import javax.inject.Inject;
    6. @QuarkusMain
    7. @CommandLine.Command(name = "demo", mixinStandardHelpOptions = true)
    8. public class ExampleApp implements Runnable, QuarkusApplication {
    9. @Inject
    10. CommandLine.IFactory factory; (1)
    11. @Override
    12. public void run() {
    13. // business logic
    14. }
    15. @Override
    16. public int run(String... args) throws Exception {
    17. return new CommandLine(this, factory).execute(args);
    18. }
    19. }
    1Quarkus-compatible CommandLine.IFactory bean created by picocli extension.

    Native mode support

    This extension uses the Quarkus standard build steps mechanism to support GraalVM Native images. In the exceptional case that incompatible changes in a future picocli release cause any issue, the following configuration can be used to fall back to the annotation processor from the picocli project as a temporary workaround:

    For Gradle, you need to add the following in dependencies section of the build.gradle file:

    1. annotationProcessor enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")

    Configuration Reference