Search code examples
javamicronautpicocli

Appropriate way to implement a cli Application which also uses the service profile with Micronaut


I've no problem in creating a REST Server or a Picocli CLI Application. But what if I want to have both in one Application?

The thing is, I want to have an Application which provides some business logic via REST Server (no problem there), but in some other cases I want to trigger the business logic via CLI without starting the HTTP Server (eg. for CI/CD).

I'm not sure if I run into problems if I start the app via PicocliRunner.run(Application.class, args) and if a specific argument is given run the Server with Micronaut.run(Application.class);, since they create a different context.

Does anyone know a proper way to achieve this?

This is how I solved it:

import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.runtime.Micronaut;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;

@Command(
        name = "RestAndCliExample",
        description = "...",
        mixinStandardHelpOptions = true
)
public class Application implements Runnable {
    private enum Mode {serve, run}

    @Parameters(index = "0", description = "Execution mode: ${COMPLETION-CANDIDATES}")
    private Mode mode;

    public static void main(String[] args) throws Exception {
        args = new String[]{"run"};
        PicocliRunner.run(Application.class, args);
    }

    public void run() {
        if (Mode.serve.equals(mode)) {
            // Start REST API
            Micronaut.run(Application.class);
        } else {
            // TODO run code directly
        }
    }
}

Solution

  • One way to accomplish this is to @Inject the ApplicationContext into your @Command-annotated class. This allows your command to use the same application context instead of needing to start a separate one.

    Then, in your run method, you can start the REST server by obtaining the EmbeddedServer from the application context and calling start on it, or you can execute the functionality directly without the REST server.

    See also this answer for more detail: https://stackoverflow.com/a/56751733/1446916