Writing aggregates in Java

In the Eventuate programming model, the majority of your application’s business logic is implemented by aggregates. An aggregate does two things:

  1. Processes commands and returns events, which leaves the state of the aggregate unchanged.
  2. Consumes events, which updates its state.

The Eventuate client framework for Java provides a number of ways to define aggregates. The easiest approach is for your aggregate class to extend ReflectiveMutableCommandProcessingAggregate.

Using ReflectiveMutableCommandProcessingAggregate

ReflectiveMutableCommandProcessingAggregate is a generic abstract class that has two type parameters: the aggregate type and the aggregate’s command superinterface. As the name suggests, it uses reflection to invoke the appropriate handler method for each command and event. Here is the Java version of an Account aggregate.

public class Account
   extends ReflectiveMutableCommandProcessingAggregate<Account, AccountCommand> {

  private BigDecimal balance;

  public List<Event> process(OpenAccountCommand cmd) {
    return EventUtil.events(new AccountOpenedEvent(cmd.getInitialBalance()));
  }

  public List<Event> process(DebitAccountCommand cmd) {
    if (balance.compareTo(cmd.getAmount()) < 0)
      return EventUtil.events(
        new AccountDebitFailedDueToInsufficientFundsEvent(cmd.getTransactionId()));
    else
      return EventUtil.events(
         new AccountDebitedEvent(cmd.getAmount(), cmd.getTransactionId()));
  }

  public List<Event> process(CreditAccountCommand cmd) {
    return EventUtil.events(
         new AccountCreditedEvent(cmd.getAmount(), cmd.getTransactionId()));
  }

  public void apply(AccountOpenedEvent event) {
    balance = event.getInitialBalance();
  }

  public void apply(AccountDebitedEvent event) {
    balance = balance.subtract(event.getAmount());
  }

  public void apply(AccountDebitFailedDueToInsufficientFundsEvent event) {
  }

  public void apply(AccountCreditedEvent event) {
    balance = balance.add(event.getAmount());
  }

  public BigDecimal getBalance() {
    return balance;
  }
}

Account extends ReflectiveMutableCommandProcessingAggregate. It defines several process() methods, one for each command type. A process() handles a command and returns a list of Events.

Several apply() methods also exist, one for each event type. An apply() method consumes an event and changes the state of the aggregate.

Extending CommandProcessingAggregate

An alternative way to define an aggregate class is to implement the CommandProcessingAggregate interface directly. You will need to implement the processCommand() and applyEvent() methods yourself.


Stay in touch
Copyright © 2021 Eventuate, Inc • All rights reserved.