Annotation Interface InterceptApply


@Documented @Retention(RUNTIME) @Target(METHOD) public @interface InterceptApply
Indicates that a method should intercept and potentially transform an update before it is applied to an entity.

This annotation is typically used to:

  • Suppress updates that should be ignored
  • Rewrite or correct invalid updates
  • Split a single update into multiple updates

Interceptors are invoked before any @Apply or @AssertLegal methods. If multiple interceptors match, they are invoked recursively until the result stabilizes.

Interceptors can return:

  • The original update (no change)
  • null or void to suppress the update
  • An Optional, Collection, or Stream to emit zero or more updates
  • A different object to replace the update

Interaction with legality assertions

Interception fully determines the effective update sequence before @AssertLegal and @Apply are considered:
  • A retained update runs its matching immediate assertions before it is applied.
  • A suppressed update runs neither its assertions nor its apply methods.
  • A replacement runs assertions for the replacement, not for the original update.
  • Expanded updates are asserted and applied in encounter order. Each update's immediate assertions see the state produced by earlier updates.
Assertions configured with @AssertLegal(afterHandler = true) remain deferred until handler completion. If an invariant must survive replacement, define it for the effective replacement (or in shared/entity-side logic) rather than relying on an assertion that only matches the original update.

Method parameters are automatically injected and may include:

  • The current entity (if it exists)
  • Any parent or ancestor entity in the aggregate
  • The update object (if defined on the entity side)
  • Context like Metadata, Message, or User

Note that empty entities (where the value is null) are not injected unless the parameter is annotated with @Nullable.

Examples

1. Rewrite a duplicate create into an update (inside the update class)

@InterceptApply
UpdateProject resolveDuplicateCreate(Project project) {
    // If this method is invoked, the Project already exists
    return new UpdateProject(projectId, details);
}

2. Suppress a no-op update

@InterceptApply
Object ignoreNoChange(Product product) {
    if (product.getDetails().equals(details)) {
        return null; // suppress update
    }
    return this;
}

Note: You typically do not need to implement this kind of check manually if the enclosing @Aggregate or specific @Apply method is configured with IF_MODIFIED. That configuration ensures that no event is stored or published if the entity is not modified.

3. Expand a bulk update into individual operations

@InterceptApply
List<CreateTask> explodeBulkCreate() {
    return tasks;
}

4. Recursive interception

If the result of one @InterceptApply method is a new update object, Fluxzero will look for matching interceptors for the new value as well — continuing recursively until no further changes occur.

See Also: