Command
Marks a commanding method.
A commanding method must:
- be annotated with @Command;
- accept one of the following as the first parameter:
- a command message;
- an event message;
- a rejection message.
Like other message-handling methods, commanding methods are designed to be called by the framework only. Therefore, it is recommended to declare them as package-private. It discourages a developer from calling these methods directly from anywhere.
Package-private access level still declares that a command handler method is a part of the Bounded Context-level API. See the BoundedContext description on how the packages and Bounded Contexts relate.
Command Transformation
Commanding methods may be used to transform an incoming command with one or more commands. In this case the first method parameter must extend io.spine.base.CommandMessage. The returning values must derive from the io.spine.base.CommandMessage as well.
If a commanding method accepts a command type which is also handled by the application by another method, a run-time error will occur. This also means that an application cannot have two command-handling methods that accept the same command type.
Accepted Parameters
There are several combinations of accepted parameters for a command-transforming method. The set of available parameters include
- single command message:
@Command ArchiveTask on(DeleteTask command) { ... }
Content copied to clipboard - a command message along with its context:
@Command MoveTaskToDone on(CompleteTask command, CommandContext context) { ... }
Content copied to clipboard
Returning Values
A command-transforming method always returns an outcome. Depending on the design intention, a type of outcome may vary.
The command-transforming method must return either
- a command message:
@Command AssignTask on(StartTask command) { ... }
Content copied to clipboard - one of of several command messages:
@Command EitherOf2<StopTask, PauseTask> on(RemoveTaskFromProject command) { ... }
Content copied to clipboard - an
Iterable
of command messages:@Command Iterable<PauseTask> on(PauseProject command) { ... }
Content copied to clipboard - a tuple of several command messages; being similar to
Iterable
, tuples allow to declare the exact types of returning values, includingOptional
values:@Command Pair<AssignTask, Optional<StartTask>> on(AddTaskToProject command) { ... }
Content copied to clipboard
Rejecting Commands
As a command-handling method, a command-transforming method may reject an incoming command. In this case, it should declare a generated class derived from ThrowableMessage in throws
clause:
@Command
AssignProject on(CreateProject command) throws CannotCreateProject { ... }
Throwing other types of Throwable
s is not allowed in the command-transforming methods.
Command Reaction
A commanding method may serve to emit commands in response to an incoming event. In this case its first parameter must be a message of either EventMessage or RejectionMessage type.
Accepted Parameters
Command-reaction method must accept either
- single event message:
@Command ScheduleDelivery on(OrderPaid command) { ... }
Content copied to clipboard - an event message along with its context:
@Command NotifyCustomer on(DeliveryScheduled event, EventContext context) { ... }
Content copied to clipboard - a rejection message:
@Command CreateProject on(Rejections.CannotCreateProject rejection) { // Change the parameters and try again. }
Content copied to clipboard - a rejection message along with the context of the command which caused it:
@Command ReassignTask on(Rejections.CannotStartTask rejection, CommandContext) { ... }
Content copied to clipboard
It is possible to receive external Events and Rejections. For that, mark the message parameter with the @External annotation. External Commands do not travel this way.
Returning Values
A command-reacting method may emit one or more messages deriving from CommandMessage. The possibilities for the return values are flexible. They serve to describe the returning values as sharp as possible and thus reduce the probability of a human mistake.
A command-reacting method must return either
- a command message:
@Command ArchiveTask on(TaskCompleted event) { ... }
Content copied to clipboard - an
Optional
command message:@Command Optional<StartTask> on(TaskAdded event) { ... }
Content copied to clipboard - one of of several command messages:
@Command EitherOf2<StopTask, PauseTask> on(TaskReassigned event) { ... }
Content copied to clipboard - an
Iterable
of command messages:@Command List<ArchiveTask> on(ProjectCompleted event) { ... }
Content copied to clipboard - a tuple of several command messages; it allows to declare the exact types of returning values, including
Optional
s:@Command Triplet<AssignTask, UpdateTaskDueDate, Optional<StartTask>> on(TaskCreated command) { ... }
Content copied to clipboard
If the annotation is applied to a method which doesn't satisfy either of these requirements, this method is not considered a commanding method and is not registered for command generation.