Axon 2.0 - @AggregateIdentifier usage

Hi,

Something broke during the last couple of days, and none our
aggregates do not seem to work any more. I assume that
AbstractAnnotatedAggregateRootTest.SimpleAggregateRoot is not quite up
to date with how aggregates should be build?

our aggregates looks like the following, and worked until yesterday:

class AR extends AbstractAnnotatedAggregateRoot {

  @AggregateIdentifier
  String id;

  public AR() {}

  publicAR(Object argument) {
    this.id = UUID.randomUUID().toString();
    apply(new ARCreatedEvent(id, argument));
  }

}

Adding an

@EventHandler
public void handle(ARCreatedEvent event) {this.id = event.getId();}

fixes the issue but shouldn't be needed right?

Attaching the stack trace from one of our failing tests

Cheers
Sebastian

org.axonframework.test.AxonAssertionError: The published events do not
match the expected events

Expected |
Actual
-------------------------------------------------------------------|-------------------------------------------------------------------
com.casumo.platform.components.bonus.api.events.BonusExpiredEvent <|>

A probable cause for the wrong chain of events is an exception that
occurred while handling the command.
org.axonframework.eventsourcing.IncompatibleAggregateException:
AggregateIdentifier is unknown in
[com.casumo.platform.components.bonus.command.domain.Bonus]. Make sure
the Aggregate Identifier is initialized before registering events.
    at
org.axonframework.domain.AbstractAggregateRoot.getEventContainer(AbstractAggregateRoot.java:
164)
    at
org.axonframework.domain.AbstractAggregateRoot.initializeEventStream(AbstractAggregateRoot.java:
135)
    at
org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot.initializeState(AbstractEventSourcedAggregateRoot.java:
66)
    at
org.axonframework.eventsourcing.EventSourcingRepository.doLoad(EventSourcingRepository.java:
158)
    at
org.axonframework.eventsourcing.EventSourcingRepository.doLoad(EventSourcingRepository.java:
52)
    at
org.axonframework.repository.AbstractRepository.load(AbstractRepository.java:
64)
    at
org.axonframework.repository.LockingRepository.load(LockingRepository.java:
118)
    at
org.axonframework.repository.AbstractRepository.load(AbstractRepository.java:
74)
    at
com.casumo.platform.components.bonus.command.commandhandlers.BonusCommandHandler.handle(BonusCommandHandler.java:
66)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at
org.axonframework.common.annotation.MethodMessageHandler.invoke(MethodMessageHandler.java:
105)
    at
org.axonframework.common.annotation.MessageHandlerInvoker.invokeHandlerMethod(MessageHandlerInvoker.java:
79)
    at
org.axonframework.commandhandling.annotation.AnnotationCommandHandlerAdapter.handle(AnnotationCommandHandlerAdapter.java:
92)
    at
org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:
62)
    at
org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:
68)
    at org.axonframework.test.GivenWhenThenTestFixture
$AggregateRegisteringInterceptor.handle(GivenWhenThenTestFixture.java:
382)
    at
org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:
60)
    at
org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:
68)
    at
org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:
117)
    at
org.axonframework.commandhandling.SimpleCommandBus.dispatch(SimpleCommandBus.java:
94)
    at
org.axonframework.test.GivenWhenThenTestFixture.when(GivenWhenThenTestFixture.java:
174)
    at
com.casumo.platform.components.bonus.command.commandhandlers.BonusCommandHandlerTest.testExpireBonus_bonusGetsExpired(BonusCommandHandlerTest.java:
324)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod
$1.runReflectiveCall(FrameworkMethod.java:44)
    at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:
15)
    at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:
41)
    at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:
20)
    at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:
28)
    at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:
31)
    at
org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:
79)
    at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
71)
    at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:
191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:
184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at
org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:
37)
    at
org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at
org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:
51)
    at
org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:
63)
    at
org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:
49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
35)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
24)
    at
org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:
32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter
$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:75)
    at $Proxy2.processTestClass(Unknown Source)
    at
org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:
91)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
35)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
24)
    at
org.gradle.messaging.remote.internal.TypeCastDispatch.dispatch(TypeCastDispatch.java:
30)
    at
org.gradle.messaging.remote.internal.WorkerProtocol.handleIncoming(WorkerProtocol.java:
53)
    at
org.gradle.messaging.remote.internal.WorkerProtocol.handleIncoming(WorkerProtocol.java:
31)
    at org.gradle.messaging.remote.internal.ProtocolStack
$ProtocolStage.handleIncoming(ProtocolStack.java:167)
    at org.gradle.messaging.remote.internal.ProtocolStack
$BottomStage.handleIncoming(ProtocolStack.java:277)
    at org.gradle.messaging.remote.internal.ProtocolStack
$BottomConnection$1.run(ProtocolStack.java:299)
    at org.gradle.messaging.remote.internal.ProtocolStack
$ExecuteRunnable.dispatch(ProtocolStack.java:120)
    at org.gradle.messaging.remote.internal.ProtocolStack
$ExecuteRunnable.dispatch(ProtocolStack.java:116)
    at
org.gradle.messaging.dispatch.AsyncDispatch.dispatchMessages(AsyncDispatch.java:
132)
    at org.gradle.messaging.dispatch.AsyncDispatch.access
$000(AsyncDispatch.java:33)
    at org.gradle.messaging.dispatch.AsyncDispatch
$1.run(AsyncDispatch.java:72)
    at org.gradle.messaging.concurrent.DefaultExecutorFactory
$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66)
    at java.util.concurrent.ThreadPoolExecutor
$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor
$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

    at
org.axonframework.test.ResultValidatorImpl.expectPublishedEvents(ResultValidatorImpl.java:
80)
    at
org.axonframework.test.ResultValidatorImpl.expectEvents(ResultValidatorImpl.java:
65)
    at
com.casumo.platform.components.bonus.command.commandhandlers.BonusCommandHandlerTest.testExpireBonus_bonusGetsExpired(BonusCommandHandlerTest.java:
324)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod
$1.runReflectiveCall(FrameworkMethod.java:44)
    at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:
15)
    at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:
41)
    at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:
20)
    at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:
28)
    at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:
31)
    at
org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:
79)
    at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
71)
    at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:
191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:
184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at
org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:
37)
    at
org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at
org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:
51)
    at
org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:
63)
    at
org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:
49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
35)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
24)
    at
org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:
32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter
$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:75)
    at $Proxy2.processTestClass(Unknown Source)
    at
org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:
91)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
35)
    at
org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:
24)
    at
org.gradle.messaging.remote.internal.TypeCastDispatch.dispatch(TypeCastDispatch.java:
30)
    at
org.gradle.messaging.remote.internal.WorkerProtocol.handleIncoming(WorkerProtocol.java:
53)
    at
org.gradle.messaging.remote.internal.WorkerProtocol.handleIncoming(WorkerProtocol.java:
31)
    at org.gradle.messaging.remote.internal.ProtocolStack
$ProtocolStage.handleIncoming(ProtocolStack.java:167)
    at org.gradle.messaging.remote.internal.ProtocolStack
$BottomStage.handleIncoming(ProtocolStack.java:277)
    at org.gradle.messaging.remote.internal.ProtocolStack
$BottomConnection$1.run(ProtocolStack.java:299)
    at org.gradle.messaging.remote.internal.ProtocolStack
$ExecuteRunnable.dispatch(ProtocolStack.java:120)
    at org.gradle.messaging.remote.internal.ProtocolStack
$ExecuteRunnable.dispatch(ProtocolStack.java:116)
    at
org.gradle.messaging.dispatch.AsyncDispatch.dispatchMessages(AsyncDispatch.java:
132)
    at org.gradle.messaging.dispatch.AsyncDispatch.access
$000(AsyncDispatch.java:33)
    at org.gradle.messaging.dispatch.AsyncDispatch
$1.run(AsyncDispatch.java:72)
    at org.gradle.messaging.concurrent.DefaultExecutorFactory
$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66)
    at java.util.concurrent.ThreadPoolExecutor
$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor
$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

Hi Sebastian,

isn’t working on a snapshot exciting? ;-). The change was done a little while ago, but I think I never deployed those changes to the maven repository. Until yesterday.

The idea is that you should treat the identifier like any other property in the aggregate. The only difference is that the identifier must be set by the first event applied in the aggregate.
So in you handle(AggregateCreatedEvent), you should set the identifier to the value in the event.
Failure to do so results in this exception.

If you need more info, let me know.

Cheers,

Allard

Sure is : )

Thanks for clearing that out, it seems everything is in order then. It
seems reasonable to treat the id as any other property in most cases
but since it must be set I guess also must be annotated with
@AggregateIdentifier, why not use the annotation to signal to repo
that this is the field that should be set to the aggregate identifier?
Might as well go both ways?

Sebastian

I tried to set the identifier as part of the construction process, but that turns out to give a really ugly API. The problem is that I also want to support Aggregates that don’t use annotations. So that would mean there needs to be a “setIdentifier” kind of method, which makes it seam like an identifier is a mutable property.

Cheers,

Allard

If you don't want to have separate APIs for annotation driven ARs and
the others, that sounds reasonable (except that you already do). You
could also force non-annotation-users to set the id in the
handle(CreatedEvent e)-method and just make it easier on the ones
using annotations, just like with getIdentifier() that is not needed
when you use annotations. Anyway, no biggie... : )