October 29, 2025

CQRS With Axon Tutorial: Part 3 – Setup the Commands, Events and Aggregate

In this part, we are going to be setting up the Commands, Events and Aggregate. We also would set up the command and event handlers.We would cover the following

  1. Setup the Commands and Events Classes
  2. Setup the Aggregate
  3. Add the CommandHandlers
  4. Add the EventSourcingHandlers

 

1. Write the Command and Events

Remember that we chose Kotlin when we setup our project. The reason is that Kotlin provides a simple way of writing classes in just one line. Besides, several of such classes can be placed in a single kotlin file. Such classes are called data classes

Follow the steps below:

Step 1: Add a kotlin file in the command package. Name it api.kt. This would contain our data classes

Step 2: Write the classes for IssueCommand, IssuedEvent, RedeemCommand and RedeemedEvent. The Content of the file will be as shown below:

import org.axonframework.modelling.command.TargetAggregateIdentifier

data class IssueCommand(@TargetAggregateIdentifier val id: String, val amount: Int);
data class IssuedEvent(val id: String, val amount: Int);
data class RedeemCommand(@TargetAggregateIdentifier val id: String, val amount: Int);
data class RedeemedEvent(val id: String, val amount: Int);

Note the @TargetAggregateIdentifier annotation. This enables targeting the particular aggregate when a command is issued

 

2. Setup the Aggregate

An aggregate is “a logical group of entities that is treated as a single unit”. In this case, our aggregate would be a gift card.

To set up the aggregate:

Step 1: Create a java file in the command package. Name it GiftCard

Step 2: Annotate the class with the @Aggregate annotation

Step 3: Create a private member variable id. It would be a String.

Step 4: Annotate this variable with @AggregateIdentifier annotation

 

3. Add the CommandHandlers

CommandHandler is a function that specifies what happen when a command is executed. CommandHandlers are normally void functions with the name handle() and the take as parameter the command they are going to respond to.

Now we would add two command handlers for IssueCommand and RedeemCommand.

Step 1: Simply copy and paste the two event handlers after private variable id. Also note that I have annotated the code to explain what each part means.

   @CommandHandler
    public GiftCard(IssueCommand cmd) {
        if(cmd.getAmount()<=0)
            throw new IllegalArgumentException("amount <= 0");
        
        AggregateLifecycle.apply(new IssuedEvent(cmd.getId(), cmd.getAmount()));
    }

    @CommandHandler
    public void handle(RedeemCommand cmd) {
        if(cmd.getAmount()<=0)
            throw new IllegalArgumentException("amount <= 0");
        
        if(cmd.getAmount() > balance)
            throw new IllegalArgumentException("amount > balance");
        
        AggregateLifecycle.apply(new RedeemedEvent(cmd.getId(), cmd.getAmount()));
    }

 

Step 2: Create a private Integer field, balance in the GiftCard

Step 3: Create also an empty private constructor.

 

4. Add the EventSourcingHandlers

An EventSourcingHandler is an event executed when an event occurs. They are normally function with name on(). In this case we have two event sourcing handlers.

Step 1: Copy and Paste the code after the command handlers

    @EventSourcingHandler
    public void on(IssuedEvent evt){
        //for a new card, the amount is the balance
        id = evt.getId();
        balance = evt.getAmount();
    }

    @EventSourcingHandler
    public void on(RedeemedEvent evt) {
        //update the balance when a card is redeemed
        balance = balance - evt.getAmount();
    }

 

So we’ve completed writing the handlers. I would recommend you build the project. Just to make sure everything is fine.

 

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments