Annotation Interface Apply


Indicates that a method or constructor applies an update to an entity, or creates or deletes an entity.

An @Apply method defines how a specific update modifies an entity. This update is typically the payload of a command or other message expressing intent. Once validated and applied, the update may be published and/or stored as an event, depending on the publication configuration.

@Apply can be placed:

  • On a method inside the update class (e.g. UpdateProduct#apply(Product)), which receives the current state of the entity and returns the updated version
  • On a method or static factory in the entity class itself (e.g. Product#update(UpdateProduct)), which describes how the entity processes a given update
  • On a constructor or static method of the entity, if the update creates a new instance

For deletions, returning null signals that the entity should be removed.

When the entity is part of a larger aggregate, Flux automatically routes the update to the correct entity instance using matching identifier fields, typically annotated with EntityId.

@Apply methods are also used during event sourcing to reconstruct an entity's state from past updates.

Method parameters are injected automatically. Supported parameters include:

  • The current entity instance (for non-static apply methods)
  • Any parent, grandparent, or other ancestor entity in the aggregate hierarchy
  • The update object itself
  • The full Message or its Metadata
  • Other context such as the User performing the update

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

Examples

1. Creating a new entity from an @Apply method inside the update class


 @Apply
 Issue create() {
     return Issue.builder()
                 .issueId(issueId)
                 .count(1)
                 .status(IssueStatus.OPEN)
                 .details(issueDetails)
                 .firstSeen(lastSeen)
                 .lastSeen(lastSeen)
                 .build();
 }
 

2. Updating an entity with a new state


 @Apply
 Product apply(Product product) {
     return product.toBuilder().details(details).build();
 }
 

3. Deleting an entity


 @Apply
 Product apply(Product product) {
     return null;
 }
 

4. Defining apply methods inside the entity class


 @Apply
 static Product create(CreateProduct update) {
     return Product.builder()
                   .productId(update.getProductId())
                   .details(update.getDetails())
                   .build();
 }

 @Apply
 Product update(UpdateProduct update) {
     return this.toBuilder().details(update.getDetails()).build();
 }

 @Apply
 Product delete(DeleteProduct update) {
     return null;
 }
 

Routing example with aggregates and nested entities


 @Aggregate
 class ProductCategory {
     String categoryId;

     @Member
     List<Product> products;
 }
 
Updates targeting `Product` will automatically be routed based on `@EntityId` inside `Product`.
See Also:
  • Element Details

    • eventPublication

      EventPublication eventPublication
      Controls whether the update should result in a published update, depending on whether the entity was actually modified.

      This overrides the default from the enclosing aggregate, if set.

      Returns:
      update publication behavior
      Default:
      DEFAULT
    • publicationStrategy

      EventPublicationStrategy publicationStrategy
      Controls how the applied update is stored and/or published. This strategy takes precedence over eventPublication() if explicitly set.
      Returns:
      strategy for persisting and/or publishing the applied update
      Default:
      DEFAULT