Yet another "Make sure the Aggregate Identifier is initialized before registering events."

Hello,

I have encountered the AggregateIdentifierNotInitializedException problem, which I am not able to solve. I have tried everything found on this group, and still not sure why it’s not working.
The exception occurs after creating the Aggregate, when I try to update it via a Command by using repository load in command handler.

I am using Axon 2.4.5 and Spring Boot 1.4.2.

Below is how I create the Aggregate

public class IdentityAgg extends AbstractAnnotatedAggregateRoot implements Serializable {

    private static final long serialVersionUID = 8832894803205334145L;

    @AggregateIdentifier
    private String id;

    private String type;

    private String name;

    private List<Contact> contactList;

    public IdentityAgg() {}

    public IdentityAgg(String id, String type, String name) {
        apply(new IdentityCreatedEvent(id, type, name));
    }

    @EventSourcingHandler
    public void handle(IdentityCreatedEvent event) {
        this.id = event.getIdentityId();
        this.type = event.getType();
        this.name = event.getName();
    }

And this is how I update the Aggregate

@Component
public class ContactCommandHandler {

    @Autowired
    private Repository repository;

    @CommandHandler
    public void handle(RegisterNewContactCommand registerNewContactCommand) throws OPNSException {
        IdentityAgg identityAggToAddWithin = (IdentityAgg) repository.load(registerNewContactCommand.getIdentityId()); // this line is throwing the exception
        identityAggToAddWithin.addContact(registerNewContactCommand.getIdentityId(), registerNewContactCommand.getContact());
    }

AFAICT you’re missing @CommandHandler on the second constructor.

Jorg

Thanks for your answer, actually I don’t think this is the issue, because the second constructor is not being invoked directly by a command, there is another command which calls it.
Here is the code which calls the second constructor from within a command handler :

@Component
public class IdentityCommandHandler {

    @Autowired
    private Repository<IdentityAgg> repository;

    @CommandHandler
    public void handle(CreateIdentityCommand createIdentityCommand {
        
        IdentityAgg identityAgg =
                new IdentityAgg(createIdentityCommand.getIdentityId(),createIdentityCommand.getType(),createIdentityCommand.getName());
        repository.add(identityAgg);

    }
}

I’ve forgot to mention that the Aggregate is being stored in the event store, and I am using the JdbcEventStore as an implementation

I don’t think this is supported. The @CommandHandler needs to be on an AR constructor and Axon needs to route the command to that constructor so that it knows to create a new AR in the store.

I wish it was that simple :). Anyway I’ve just modified as you suggested, and this is how my code looks right now. But still no success, even more, now the aggregate is not being inserted into event store anymore.

This is how I send the command :

commandGateway.send(new CreateIdentityCommand(uuid,
        identityTypeAndName.getType(), identityTypeAndName.getName()));

This is how my constructor looks now:

@CommandHandler
public IdentityAgg(CreateIdentityCommand createIdentityCommand) {
    apply(new IdentityCreatedEvent(createIdentityCommand.getIdentityId(), createIdentityCommand.getType(), createIdentityCommand.getName()));
}

@EventSourcingHandler
public void handle(IdentityCreatedEvent event) {
    this.id = event.getIdentityId();
    this.type = event.getType();
    this.name = event.getName();
}

And this is the command object (p.s: I’ve already tried to use the @TargetAggregateIdentifier annotation, but no difference :), and by reading the docs, I know why :slight_smile: )

public class CreateIdentityCommand {

    private final String identityId;

    private final String type;

    private final String name;

    public CreateIdentityCommand(String identityId, String type, String name) {
        this.identityId = identityId;
        this.type = type;
        this.name = name;
    }

    public String getIdentityId() {
        return identityId;
    }

    public String getType() {
        return type;
    }

    public String getName() {
        return name;
    }
}

Thanks a lot for your help.

Hi,

@CommandHandler annotations can be put both on the aggregate itself (recommended), or on an ‘external’ bean. The latter should only be used if the command required access to external services to be executed. In that case, you may want to fetch this external information before loading (and thus acquiring a lock on) the aggregate instance.

Note that the very first event in an aggregate’s event stream must set the AggregateIdentifier. If it doesn’t, this exception is thrown. Also make sure that the value you set is non-null. I once spent too many minutes of my life debugging, only to figure out a field was never set in an Event (dev/null setter).

Cheers,

Allard

Hi Allard,

Thanks for your time, but I am still not able to make it work, in the mean time i have upgraded to axon 3.0-RC2 (using it along with spring boot 1.4.2), and as I am in development mode, I used the InMemmoryEventStorageEngine, but as soon as I switch to JdbcEventStorageEngine I get the “The aggregate identifier has not been set” exception which I guess is the same as the one used in axon 2.4.5

I don’t understand what diferrence it makes when using the Jdbc implementation, but for sure it doesn’t work.Here you can find my configuration http://pastebin.com/xs5RdftU . And this is how I create a new Agg (the command and the AggRoot) http://pastebin.com/ugNfD4y5
If you need some more info, please let me know.

I really need your help as I am stuck. I’ve read the documentation and used the axon bank example without luck.

Thanks in advance for your patience and help.

Hi Alexandru,

it’s weird that changing the StorageEngine changes the behavior of applying the event. The only thing I can image happening, is that an exception is thrown somewhere that prevents the identifier to be set, or recognized. I’d expect a stacktrace in the logs, but when things seem “weird”, I prefer not to make any assumptions at all.

Did you try configuring the JPAEventStorageEngine? I’m curious to see whether that one works.

When using Spring, use the SpringDataSourceConnectionProvider instead of the DataSourceConnectionProvider. The former will also check any existing connection used in the a Spring-managed transaction.

Cheers,

Allard

Hi Allard,

Sorry for the late response, I’ve been in a small holiday.

So, I’ve updated to Axon 3.0 (no more RC-2) and added JpaEventStorageEngine instead of Jdbc. Unfortunately I have the same issue.
By the way I am using Oracle as underlying databse.

The exception occurs in EventSourcedAggregate in the publish method.

Please let me know what other info is needed in order to be able tu investigate further this problem.

Thanks !


@Override
protected void publish(EventMessage<?> msg) {
    if (msg instanceof DomainEventMessage) {
        lastEventSequenceNumber = ((DomainEventMessage) msg).getSequenceNumber();
    }
    snapshotTrigger.eventHandled(msg);
    super.publish(msg);
    if (identifierAsString() == null) {
        throw new 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 have investigated further trying to understand what is really going on.

So far I’ve found that no matter what AggregateFactory I use (either Generic or SpringPrototype) somehow in createAggregateRoot method the Aggregate is never initialized with the DomainEventMessage firstEvent.

In the GenericAggregateFactory if (aggregateBaseType.isAssignableFrom(firstEvent.getPayloadType())) statement is getting always false, because the agregate base type is of type “IdentityAgg” and the event payload type is “IdentityCreatedEvent”, which is correct, but that means a new instance of IdentityAgg will be created, which will lead to the indentifier to be null causing the exception.

Also in SpringPrototypeAggregateFactory the createAggregateRoot method returns an IdentityAgg but with null fields, also triggering the above mentioned exception

I might be wrong, but this is all I could found by debugging trough axon core :slight_smile:

Hi Alexandru,

the AggregateFactory should deliver initialized aggregates, so it’s fine that the value for the identifier is null at that point. This exception is raised when the identifier is not set to a non-null value after the first event has been applied (IdentityCreatedEvent in your case). That means IdentityCreatedEvent must be the first event, and the handler for that event must set the annotated identifier to a non-null value.

That said, is you identifier field annotated with @AggregateIdentifier?

Cheers,

Allard

Hi again :slight_smile:

You can see here in this paste http://pastebin.com/ugNfD4y5 that the identifier has the mentioned annotation, also you can see the Eventhandler for the IdentityCreatedEvent.
The configuration can be found here

I agree with you but I am still a little bit confused, looking at the following method, I understand the following things :

@Override
protected EventSourcedAggregate doLoadWithLock(String aggregateIdentifier, Long expectedVersion) {
DomainEventStream eventStream = eventStore.readEvents(aggregateIdentifier);
SnapshotTrigger trigger = snapshotTriggerDefinition.prepareTrigger(aggregateFactory.getAggregateType());
if (!eventStream.hasNext()) {
throw new AggregateNotFoundException(aggregateIdentifier, “The aggregate was not found in the event store”);
}
EventSourcedAggregate aggregate = EventSourcedAggregate
.initialize(aggregateFactory.createAggregateRoot(aggregateIdentifier, eventStream.peek()),
aggregateModel(), eventStore, trigger);
aggregate.initializeState(eventStream);
if (aggregate.isDeleted()) {
throw new AggregateDeletedException(aggregateIdentifier);
}
return aggregate;
}

  1. First, the event stream is loaded from the eventstore (means it goes to the database and it gets all the events)
  2. If there are no events it means that there is no aggregate with the specified identifier
  3. Initialize the aggregate based on the stream ( bolded in the method above ) . Here the returned object has the identifier null, and you say this is normal :slight_smile:
  4. Initializing the state by calling the “publish” method for each event from event stream, and inside the “publish” method the exception is thrown. But again using the debugger the identifier it is still null, and not just the identifier, but all of the fields from within the IdentityAgg.

Checking forward I got in ModelInspector class which uses ReflectionUtils to get the field value :

@Override
public Object getIdentifier(T target) {
if (identifierField != null) {
return ReflectionUtils.getFieldValue(identifierField, target);
}
return null;
}

Here, the target object is an empty IdentityAgg so the method getFieldValue tries to get the identifier field from an empty target.

If you need some more information, please let me know, I already implemented a lot using Axon (used the in memory event store, so I couln’t catch the issue earlier) , and giving up using it is not a choice for me, so I need to solve it somehow :).

Btw thanks for making such a cool framework open source.

Regards,
Alex

Hi Alex,

I’ve tried to reconstruct your application based on the pastbin stuff you posted. It all works here. I’m unable to reproduce the issue.
If you have a means to share more of your application with me, that might help finding the issue.

Cheers,

Allard

I wish I could share you more, but I have no idea how.

Most probably it works as you don’t use an Oracle Database.

Going further with the investigation I might found something new :slight_smile: Maybe this will give you a hint on what is going on.

When the super.publish(msg) is called here :

@Override
protected void publish(EventMessage<?> msg) {
if (msg instanceof DomainEventMessage) {
lastEventSequenceNumber = ((DomainEventMessage) msg).getSequenceNumber();
}
snapshotTrigger.eventHandled(msg);
super.publish(msg);
if (identifierAsString() == null) {
throw new 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.”);
}
}

At a certain point a Handler for my IdentityCreatedEvent is searched in ModelInspector class in getHandler method, more specifically here :

protected Optional<MessageHandlingMember<? super T>> getHandler(Message<?> message) {
for (MessageHandlingMember<? super T> handler : eventHandlers) {
if (handler.canHandle(message)) {
return Optional.of(handler);
}
}
return Optional.empty();
}

The method returns Optional.empty() which is wrong due to fact that it has to process the event in order to reconstruct the state. And btw this is not happening while using the InMemmory event store, which is extremely strange.

In the eventHandlers collection I can see the corect eventhandler for my IdentityCreatedEvent, and when the handler.canHandle(message) is called, is returning false because all the conditions in bold from the method below are returning false. Not being able to find a handler it makes me think that the state of the Aggregate can’t be reconstructed.

@Override
public boolean canHandle(Message<?> message) {
return typeMatches(message) && payloadType.isAssignableFrom(message.getPayloadType()) &&
parametersMatch(message);
}

The strangest thing is that payloadType and message.PayloadType are the same

payloadType = class ro.orange.opns.publisher.cqrs.events.IdentityCreatedEvent
message.getPayloadType = class ro.orange.opns.publisher.cqrs.events.IdentityCreatedEvent
message is of type class org.axonframework.eventsourcing.GenericTrackedDomainEventMessage

P.S: I can’t make the code public, so please let me know if you have some other suggestion on how to share more with you.

Thanks Allard for your patience.

Hi,

so basically, on the breakpoint, you have two classes (can you see their ID? Usually after the @) that seem to be the same, but aren’t. This can be the case when you use a special classloader.

I have seen this once before when using Spring Boot DevTools. It may also happen with other frameworks that do automatic reloading for you. In some cases, they reload the Event classes, but not the aggregates, causing a situation like this.

Let’s hope we’re on a path to a solution here…
Cheers,

Allard

Hi,

I have attached a print screen with the debugger on, so it looks like you are right, they have different id’s. So that was the problem.

I do have Spring Boot DevTools, so basically that was the issue.
Packaging the application into a .jar file, and it works, also I removed the dependency so I can still use debug mode :slight_smile:

Well, this was a hell of an issue :slight_smile: Hopefully it will help other people too. Thanks a lot Allard for helping me solving the problem !

P.S: maybe you should mention this situation somewhere in the docs :).

2017-01-12_18-09.jpg

Hi Alexandru,

the devtools issue has come across before, but didn’t yet manifest itself in this way. That’s why it took a little while to figure out what was going on.

I’ve been trying to figure out why devtools doesn’t seem to work with the way Axon resolves annotations, but don’t have any success so far. One day, I’ll get it sorted out…

I’ll put a warning about this in the ref guide.

Cheers,

Allard

FYI: The issue has been found and fixed and a solution will be part of the next release.

That’s good news, thanks !