How to solve for AggregateIdentifierNotInitializedException?

In our case, the “real” aggregate identifier is generated when the Aggregate is saved in DB using JPA sequence table approach.

public class SomeClass extends AbstractAnnotatedAggregateRoot {
@Id

@TableGenerator(name = “_GEN”, table = “SEQUENCE”, pkColumnName = “SEQ_NAME”, valueColumnName = “SEQ_COUNT”, pkColumnValue = “_SEQ”)
@GeneratedValue(strategy = GenerationType.TABLE, generator = “_GEN”)
private Long id;

public SomeClass(String name) {

apply(new SomeClassCreatedEvent(name));
}

@EventHandler
public void on(SomeClassCreatedEvent event) {
this.name = event.getName();
}

But, Axon expects the identifier to be provided during aggregate construction for its event dispatching to work otherwise I get this exception…

Caused by: org.axonframework.domain.AggregateIdentifierNotInitializedException: AggregateIdentifier is unknown in [x.y.SomeClass]. Make sure the Aggregate Identifier is initialized before registering events.
at org.axonframework.domain.AbstractAggregateRoot.getEventContainer(AbstractAggregateRoot.java:163)
at org.axonframework.domain.AbstractAggregateRoot.registerEvent(AbstractAggregateRoot.java:72)
at org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot.apply(AbstractEventSourcedAggregateRoot.java:96)
at org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot.apply(AbstractEventSourcedAggregateRoot.java:75)
at x.y.SomeClass.(SomeClass.java:88)

I could make the @AggregateIdentifier be the “name” for Axon to be happy but it isn’t really the Id of the class. And I would like both to be the same and not do something special for Axon.
Does Axon provide a way to assign the target identifier post DB commit or it is required that the aggregate identifier be known upfront for this to work?

Regards,
Aditya

Also, I’ve tried switching to deriving from AbstractAggregateRoot and using registerEvent instead of apply. But, the problem remains the same. It looks like AbstractAggregateRoot expects a valid aggregate identifier to instantiate an event container even before the aggregate is committed. I cannot have client generated Id and I don’t want to have 2 different ids (one for Axon and one for domain). Is there a way around this?

private EventContainer getEventContainer() {
if (eventContainer == null) {
Object identifier = getIdentifier();
if (identifier == null) {
throw new AggregateIdentifierNotInitializedException(
“AggregateIdentifier is unknown in [” + getClass().getName() + "]. "

  • “Make sure the Aggregate Identifier is initialized before registering events.”);
    }
    eventContainer = new EventContainer(identifier);
    eventContainer.initializeSequenceNumber(lastEventSequenceNumber);
    }

Hi Aditya,

the requirement is that the identifier is set when the first event is applied or registered with the aggregate. Axon needs that identifier to attach it to the event.
The best way around this is to prevent database generated identifiers altogether. The best practice (in scalability, at least) is to use an identifier generated by the component that sends the create command. Just tell the DB to use that value as the identifier.

If you really must use a db generated ID, you could consider creating an aggregate without applying any events. Then, you store it to have it generate an id, and then call a method on it to change state.
Alternatively, Some DB systems allow you to specifically query for the next sequence number. That could also be an approach.

All in all, I would strongly recommend the ‘client generated identifier’ approach.

Cheers,

Allard