Parsing Arguments in Commandline Applications with Spring Boot

28.08.2018 by Jens in Spring Boot

In Commandline Applications with Spring Boot we also implemented a command line app using the CommandLineRunner interface provided by Spring. However, argument/options/parameter handling is not that good with it. Luckily, there is an even better method of writing a command line app with Spring Boot and also have good options parsing with the ApplicationRunner interface.

Notes

Before we start a quick note. In both cases, CommandLineRunner and ApplicationRunner we always can handle options with Springs property handling and the use of @Value annotation.

Full working source code is here

Get Started with ApplicationRunner

The first thing is, we create a simple Spring Boot application and implement the ApplicationRunner interface. Now, Spring can pick up our class and execute it. It similar to the CommandLineRunner.

We also must implement one method, run, but instead of a String list, we retrieve a ApplicationArguments as a parameter. That is our gate to the options, arguments, parameters or however you want to call them.

ApplicationArguments distinguish between option arguments and non-option arguments. Option arguments are the one we can use via the Spring Boot property handling (starting with like app.name=Myapp) . They can also contain multiple values per option either by passing in a comma-separated list or using the argument multiple times.

Non-option arguments are all others we pass at the command line, except VM parameters.

In the example, we will print out how many arguments of each type we received and then display them.

@SpringBootApplication
public class CommandlineAppApplication implements ApplicationRunner{

    public static void main(String[] args) {
        SpringApplication.run(CommandlineAppApplication.class, args);
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("# NonOptionArgs: " + args.getNonOptionArgs().size());

        System.out.println("NonOptionArgs:");
        args.getNonOptionArgs().forEach(System.out::println);

        System.out.println("# OptionArgs: " + args.getOptionNames().size());
        System.out.println("OptionArgs:");

        args.getOptionNames().forEach(optionName -> {
            System.out.println(optionName + "=" + args.getOptionValues(optionName));
        });
    }
}

Non-option arguments are reteieved via getNonOptionArgs() as a List of Strings.

And for option arguments, we can receive the option name via getOptionNames and the actual values via getOptionValues, which will return a List of Strings.

When we start the app now and pass in some arguments like:

java -jar commandline-app-0.0.1-SNAPSHOT.jar iamnonoption --app.name=CmdRulez --app.hosts=abc,def,ghi --app.name=2

We’d expect exact one non-option argument of iamnonoption and two option-arguments. app.hosts which will contain a list of [abc,def,ghi] and app.name with a list of two values.

Output of the above execution:

# NonOptionArgs: 1
NonOptionArgs:
nonoption
# OptionArgs: 2
OptionArgs:
app.hosts=[abc,def,ghi]
app.name=[CmdRulez, 2]

Conclusion

Simple and straightforward to use and we do not even have to use Springs property handling. Of course, sometimes it makes sense, sometimes not. Like with anything, “it depends”.


Want content like this in your inbox each workday? No BS, spam or tricks... just useful content:

I understand and agree to the privacy policy