Last Update: 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.
Before we start a quick note. In both cases, either CommandLineRunner or ApplicationRunner, Spring’s property handling is always supported. We can inject values using the the @Value annotation as usual.
Full working source code is here
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]
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”.