Command Registration

Defining a command registration is a first step to introducing the structure of a command and its options and parameters. This is loosely decoupled from what happens later, such as parsing command-line input and running actual target code. Essentially, it is the definition of a command API that is shown to a user.spring-doc.cn

Commands

A command in a spring-shell structure is defined as an array of commands. This yields a structure similar to the following example:spring-doc.cn

command1 sub1
command2 sub1 subsub1
command2 sub2 subsub1
command2 sub2 subsub2
We do not currently support mapping commands to an explicit parent if sub-commands are defined. For example, command1 sub1 and command1 sub1 subsub1 cannot both be registered.

Interaction Mode

Spring Shell has been designed to work on two modes: interactive (which essentially is a REPL where you have an active shell instance throughout a series of commands) and non-interactive (where commands are executed one by one from a command line).spring-doc.cn

Differentation between these modes is mostly around limitations about what can be done in each mode. For example, it would not be feasible to show what was a previous stacktrace of a command if the shell is no longer active. Generally, whether the shell is still active dictates the available information.spring-doc.cn

Also, being on an active REPL session may provide more information about what the user has been doing within an active session.spring-doc.cn

Options

Options can be defined as long and short, where the prefixing is -- and -, respectively. The following examples show long and short options:spring-doc.cn

CommandRegistration.builder()
	.withOption()
		.longNames("myopt")
		.and()
	.build();
CommandRegistration.builder()
	.withOption()
		.shortNames('s')
		.and()
	.build();

Target

The target defines the execution target of a command. It can be a method in a POJO, a Consumer, or a Function.spring-doc.cn

Method

Using a Method in an existing POJO is one way to define a target. Consider the following class:spring-doc.cn

public static class CommandPojo {

	String command(String arg) {
		return arg;
	}
}

Given the existing class shown in the preceding listing, you can then register its method:spring-doc.cn

CommandPojo pojo = new CommandPojo();
CommandRegistration.builder()
	.command("command")
	.withTarget()
		.method(pojo, "command")
		.and()
	.withOption()
		.longNames("arg")
		.and()
	.build();

Function

Using a Function as a target gives a lot of flexibility to handle what happens in a command execution, because you can handle many things manually by using a CommandContext given to a Function. The return type from a Function is then what gets printed into the shell as a result. Consider the following example:spring-doc.cn

CommandRegistration.builder()
	.command("command")
	.withTarget()
		.function(ctx -> {
			String arg = ctx.getOptionValue("arg");
			return String.format("hi, arg value is '%s'", arg);
		})
		.and()
	.withOption()
		.longNames("arg")
		.and()
	.build();

Consumer

Using a Consumer is basically the same as using a Function, with the difference being that there is no return type. If you need to print something into a shell, you can get a reference to a Terminal from a context and print something through it. Consider the following example:spring-doc.cn

CommandRegistration.builder()
	.command("command")
	.withTarget()
		.consumer(ctx -> {
			String arg = ctx.getOptionValue("arg");
			ctx.getTerminal().writer()
				.println(String.format("hi, arg value is '%s'", arg));
		})
	.and()
	.withOption()
		.longNames("arg")
		.and()
	.build();