Command

@Retention(value = RUNTIME)
@Target(value = METHOD)
public @interface 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) { ... }
    
  • a command message along with its context:
    @Command
     MoveTaskToDone on(CompleteTask command, CommandContext context) { ... }
    

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) { ... }
    
  • one of of several command messages:
    @Command
    EitherOf2<StopTask, PauseTask> on(RemoveTaskFromProject command) { ... }
    
  • an Iterable of command messages:
    @Command
    Iterable<PauseTask> on(PauseProject command) { ... }
    
  • a tuple of several command messages; being similar to Iterable, tuples allow to declare the exact types of returning values, including Optional values:
    @Command
    Pair<AssignTask, Optional<StartTask>> on(AddTaskToProject command) { ... }
    

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 Throwables 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) { ... }
    
  • an event message along with its context:
    @Command
     NotifyCustomer on(DeliveryScheduled event, EventContext context) { ... }
    
  • a rejection message:
    @Command
     CreateProject on(Rejections.CannotCreateProject rejection) {
         // Change the parameters and try again.
     }
    
  • a rejection message along with the context of the command which caused it:
    @Command
     ReassignTask on(Rejections.CannotStartTask rejection, CommandContext) { ... }
    

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) { ... }
    
  • an Optional command message:
    @Command
    Optional<StartTask> on(TaskAdded event) { ... }
    
  • one of of several command messages:
    @Command
    EitherOf2<StopTask, PauseTask> on(TaskReassigned event) { ... }
    
  • an Iterable of command messages:
    @Command
    List<ArchiveTask> on(ProjectCompleted event) { ... }
    
  • a tuple of several command messages; it allows to declare the exact types of returning values, including Optionals:
    @Command
    Triplet<AssignTask, UpdateTaskDueDate, Optional<StartTask>> on(TaskCreated command) { ... }
    

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.

See also

Returning Two or More Command Messages

Returning One of Command Messages

Handling Commands

Functions

Link copied to clipboard
public abstract boolean external()
When true, the annotated method receives an event generated from outside the Bounded Context to which the annotated method's class belongs.

Inherited functions

Link copied to clipboard
public abstract Class<? extends Annotation> annotationType()
Link copied to clipboard
public abstract boolean equals(Object p)
Link copied to clipboard
public abstract int hashCode()
Link copied to clipboard
public abstract String toString()