@CreationPolicy(AggregateCreationPolicy.CREATE_IF_MISSING) not working

Hey

I found weird behaviour of @CreationPolicy(AggregateCreationPolicy.CREATE_IF_MISSING) aggregate command handler.

My code:

package pl.echoslowa.web.domain.aggregate;

import lombok.NoArgsConstructor;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.eventsourcing.EventSourcingHandler;
import org.axonframework.modelling.command.AggregateCreationPolicy;
import org.axonframework.modelling.command.AggregateIdentifier;
import org.axonframework.modelling.command.CreationPolicy;
import org.axonframework.spring.stereotype.Aggregate;
import pl.echoslowa.web.domain.UserDomain;

import static org.axonframework.modelling.command.AggregateLifecycle.apply;
import static pl.echoslowa.web.domain.UserDomain.UserDataUpdatedEvent;

@Aggregate
@NoArgsConstructor
public class UserDataAggregate {

    @AggregateIdentifier
    private String userAccountId;

    @CommandHandler
    @CreationPolicy(AggregateCreationPolicy.CREATE_IF_MISSING)
    public String handle(UserDomain.UserDataUpdateCommand c) {
        apply(new UserDataUpdatedEvent(c.userAccountId(), c.userDataEntity()));
        return c.userAccountId();
    }

    @EventSourcingHandler
    private void on(UserDomain.UserDataUpdatedEvent e) {
        userAccountId = e.userAccountId();
    }
}

And messages:

record UserDataUpdateCommand(@TargetAggregateIdentifier String userAccountId, @NotNull UserDataEntity userDataEntity){}
record UserDataUpdatedEvent(String userAccountId, UserDataEntity userDataEntity){}

When I send command with @TargetAggregateIdentifier having value as another aggregate of different type, I’m getting error:

org.axonframework.eventsourcing.IncompatibleAggregateException: Aggregate identifier must be non-null after applying an event. Make sure the aggregate identifier is initialized at the latest when handling the creation event.

I tried to debug with Java debugger - but the command handler code is not even executed.

When I put different identifier (that doesn’t exist for any other aggregate type) or when I change policy to AggregateCreationPolicy.ALWAYS the command is handled properly.

My guess it that, there might be bug, that for CREATE_IF_MISSING policy, there’s check if aggregate for given @TargetAggregateIdentifier exists in event store, but the aggregate type is ignored in such check.

I’m using Axon Server.

Can any have some hint if that’s factually bug in framework or I’m missing sth here?

Cześć Krzysiek!
Dzięki za pytanie.

It looks like the annotation is working correctly, but the issue lies with the usage of Axon Server. Axon Server requires unique aggregate IDs per context (The Developer and Starter plans only support 1 (non-admin) context). I see 2 solution for the problem:

  • Use multiple contexts in Axon Server. Actually, this is typically the case - if objects have the same ID, it usually (while modeling with DDD approach) means they are different representations in different Bounded Contexts. This may require more adjustments in your application. You can read more about it here: Multi-Context

  • Solution for AxonSever with single context setup: add the aggregate type to its ID value. You can even have a complex object as an ID (like record AggregateId(String type, String value) { String toString() { return type + ":" + value; } } ). The important thing is that the toString() of this object returns something globally unique across all aggregate types.

Hope this helps!
Mateusz

1 Like