Class EventSourcedEntity<S,E>

Object
akka.javasdk.eventsourcedentity.EventSourcedEntity<S,E>
Type Parameters:
S - The type of the state for this entity.
E - The parent type of the event hierarchy for this entity. Required to be a sealed interface.

public abstract class EventSourcedEntity<S,E> extends Object
The Event Sourced state model captures changes to data by storing events in a journal. The current entity state is derived from the persisted events.

When implementing an Event Sourced Entity, you first define what will be its internal state (your domain model), the commands it will handle and the events it will persist to modify its state.

Each command is handled by a command handler. Command handlers are methods returning an EventSourcedEntity.Effect. When handling a command, you use the Effect API to:

  • persist events and build a reply
  • directly returning to the caller if the command is not requesting any state change
  • rejected the command by returning an error
  • instruct the runtime to delete the entity

Each event is handled by the applyEvent(E) method. Events are required to inherit from a common sealed interface, and it's recommend to implement the applyEvent(E) method using a switch statement. As such, the compiler can check if all existing events are being handled.

 
 // example of sealed event interface with concrete events implementing it
 public sealed interface Event {
   @TypeName("created")
   public record UserCreated(String name, String email) implements Event {};
   @TypeName("email-updated")
   public record EmailUpdated(String newEmail) implements Event {};
 }

 // example of applyEvent implementation
 public User applyEvent(Event event) {
    return switch (event) {
      case UserCreated userCreated -> new User(userCreated.name, userCreated.email);
      case EmailUpdated emailUpdated -> this.copy(email = emailUpdated.newEmail);
    }
 }
 

Concrete classes can accept the following types to the constructor:

Concrete class must be annotated with ComponentId.

  • Constructor Details

    • EventSourcedEntity

      public EventSourcedEntity()
  • Method Details

    • emptyState

      public S emptyState()
      Implement by returning the initial empty state object. This object will be made available through the currentState() method. This method is only called when the entity is initializing and there isn't yet a known state.

      Also known as "zero state" or "neutral state".

      The default implementation of this method returns null. It can be overridden to return a more sensible initial state.

    • commandContext

      protected final CommandContext commandContext()
      Additional context and metadata for a command handler.

      It will throw an exception if accessed from constructor or inside the applyEvent(E) method.

    • eventContext

      protected final EventContext eventContext()
      Additional context and metadata when handling an event in the applyEvent(E) method.

      It will throw an exception if accessed from constructor or command handler.

    • applyEvent

      public abstract S applyEvent(E event)
      This is the main event handler method. Whenever an event is persisted, this handler will be called. It should return the new state of the entity.

      Note that this method is called in two situations:

      • when one or more events are persisted by the command handler, this method is called to produce the new state of the entity.
      • when instantiating an entity from the event journal, this method is called to restore the state of the entity.
      It's important to keep the event handler side effect free. This means that it should only apply the event on the current state and return the updated state. This is because the event handler is called during recovery.

      Events are required to inherit from a common sealed interface, and it's recommend to implement this method using a switch statement. As such, the compiler can check if all existing events are being handled.

       
       // example of sealed event interface with concrete events implementing it
       public sealed interface Event {
         @TypeName("created")
         public record UserCreated(String name, String email) implements Event {};
         @TypeName("email-updated")
         public record EmailUpdated(String newEmail) implements Event {};
       }
      
       // example of applyEvent implementation
       public User applyEvent(Event event) {
          return switch (event) {
            case UserCreated userCreated -> new User(userCreated.name, userCreated.email);
            case EmailUpdated emailUpdated -> this.copy(email = emailUpdated.newEmail);
          }
       }
       
      
    • currentState

      protected final S currentState()
      Returns the state as currently stored.

      Note that modifying the state directly will not update it in storage. The state can only be updated through the applyEvent(E) method.

      This method can only be called when handling a command or an event. Calling it outside a method (eg: in the constructor) will raise a IllegalStateException exception.

      Throws:
      IllegalStateException - if accessed outside a handler method
    • effects

      protected final EventSourcedEntity.Effect.Builder<S,E> effects()