Annotation Interface AssertLegal


@Target({METHOD,FIELD,ANNOTATION_TYPE}) @Retention(RUNTIME) public @interface AssertLegal
Annotation to mark methods or fields that assert whether a command or query is legal, given the current state of an aggregate.

Can be used in two ways:

  • On methods inside a command or query class to perform legality checks directly
  • On properties of a command or query class to delegate legality checks to the annotated property’s class

Method-based usage

Annotated methods are invoked after the aggregate and its entities are loaded using Entity.assertLegal(java.lang.Object) or Entity.assertAndApply(java.lang.Object).

Parameters are injected automatically and may include:

  • The command or query object itself
  • Any matching entity from the aggregate tree (including parent or grandparent entities)
  • Other framework-specific types like Message or User

Note that empty entities (i.e., those with null values) are not injected unless the parameter is annotated with @Nullable.

Example: Validate entity does not exist yet


 @AssertLegal
 void assertNew(Issue issue) {
     throw new IllegalCommandException("Issue already exists");
 }
 

Example: Validate entity does exist


 @AssertLegal
 void assertExists(@Nullable Issue issue) {
     if (issue == null) {
         throw new IllegalCommandException("Issue not found");
     }
 }
 

Property-based usage

When placed on a field of a command or query payload (e.g., @AssertLegal UserDetails details), the framework will look for @AssertLegal methods or fields within that field’s value.

This enables modular legality checks colocated with the data they validate.

Example


 public class UpdateUser {
     UserId userId;

     @AssertLegal
     UserDetails details; // triggers @AssertLegal methods inside UserDetails
 }
 

Return value inspection

If an @AssertLegal method returns a non-null object, Flux will also inspect that return value for further @AssertLegal methods or properties. This allows for deep, composable validation logic.

Ordering

Multiple legality methods may be invoked. Their execution order is determined by priority(), with higher values taking precedence.

Execution timing

By default, checks run immediately during handler execution. You can defer them until after the handler completes (after any @Apply invocations but just before aggregate updates are committed) using afterHandler().
See Also:
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    boolean
    Determines if the legality check should be performed immediately (the default), or when the current handler is done, i.e.: after @Apply and just before the aggregate updates are committed.
    int
    Determines the order of assertions if there are multiple annotated methods.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
     
    static final int
     
    static final int
     
  • Field Details

  • Element Details

    • priority

      int priority
      Determines the order of assertions if there are multiple annotated methods. A method with higher priority will be invoked before methods with a lower priority. Use HIGHEST_PRIORITY to ensure that the check is performed first.
      Default:
      0
    • afterHandler

      boolean afterHandler
      Determines if the legality check should be performed immediately (the default), or when the current handler is done, i.e.: after @Apply and just before the aggregate updates are committed.
      Default:
      false